Skip to content

Decode HTML attribute values before URL rewriting #1480

Open

Description

@ChristianPavilonis

Problem

The HTML processor passes lol_html::Element::get_attribute text to URL rewriters. With lol_html 2.9.0, character references remain encoded and a leading U+FEFF is dropped. That differs from the attribute value a browser resolves.

Aram measured these cases while reviewing #1405 at 39adfd593:

Markup attribute Current server behavior Browser behavior
https://aim.loc.kr/identity-lockr.js Not recognized by the parsed SDK matcher Loads the Lockr SDK from the vendor host
https://static.example.com?@aim.loc.kr/identity-lockr.js Claimed as Lockr Loads from static.example.com, not Lockr
<U+FEFF>https://aim.loc.kr/identity-lockr.js Leading U+FEFF is lost and the URL is claimed as Lockr Resolves as a publisher-relative path

The encoded-slash case is a regression from the substring matcher. The encoded-question-mark and leading-BOM cases predate #1405. Permutive has the same encoded-slash limitation; GPT and Sourcepoint also parse the same undecoded attribute text.

Scope

Fix attribute-value handling once in crates/trusted-server-core/src/html_processor.rs, before the shared URL and integration attribute rewriters run. Decode character references as HTML does, and preserve the leading U+FEFF distinction rather than treating it as URL whitespace. Avoid integration-specific decoding workarounds and double decoding.

Acceptance criteria

  • Add served-HTML regression tests for src and href, including encoded slashes, &quest; before @, and leading U+FEFF.
  • Confirm rewrite ownership follows the URL a browser resolves, for Lockr and Permutive and the shared path used by other integrations.
  • Preserve ordinary URL rewriting and correct output escaping.
  • Update the accepted limitations in docs/superpowers/specs/2026-10-16-1199-sdk-url-ownership-design.md and the serverHtmlOwner corpus exception when the discrepancy is fixed.

Follow-up requested in #1405 (comment).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions