Skip to content

security: profile page renders unsanitized ENS-supplied URL #643

@rickstaa

Description

@rickstaa

Summary

The orchestrator profile renders an external website link directly from identity.url, which is sourced from the orchestrator's ENS url text record. ENS text records are user-controlled, so this value is fully attacker-controlled for any account whose ENS profile is configured.

See components/Profile/index.tsx:279:

{identity?.url && (
  <A
    variant="contrast"
    css={{ fontSize: "$2" }}
    href={identity.url}
    target="__blank"
    rel="noopener noreferrer"
  >
    ...
    {identity.url.replace(/(^\w+:|^)\/\//, "")}
  </A>
)}

Attack vectors

A malicious orchestrator can set their ENS url text record to:

  • javascript:alert(document.cookie) — when a viewer clicks the globe link, arbitrary JS runs in the explorer origin. React 16+ logs a warning for javascript: hrefs but does not reliably block them, especially after build-time minification.
  • data:text/html,<script>...</script> — opens a same-document data URL whose script can phish or impersonate the explorer.
  • evil.com/path (no scheme) — the browser treats this as a relative path, so the link navigates to https://explorer.livepeer.org/.../evil.com/path instead of the intended external site. Useful for bait-and-switch / phishing where the displayed text and the actual destination differ.

Scope

Only the website (identity.url) field is affected. The Twitter and GitHub blocks just below it interpolate the user value into hardcoded https://twitter.com/... / https://github.com/... URLs, so the protocol is fixed and they are not the same risk.

Fix

Validate the URL before rendering: auto-prefix https:// if no scheme is present, parse via new URL(...), and reject anything where protocol is not http: or https:. If sanitization fails, do not render the link block at all. Bind the sanitized value to both href and title so the user sees what they will actually navigate to.

Fix is in #644.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions