Every URL inside a <noscript> element reaches the visitor unrewritten. The proxy never sees it, so the browser contacts the third party directly.
The same URL inside and outside a noscript is treated differently. This input:
<noscript><iframe src="https://origin.example.com/tag"></iframe></noscript>
<iframe src="https://origin.example.com/tag"></iframe>
comes back as:
<noscript><iframe src="https://origin.example.com/tag"></iframe></noscript>
<iframe src="https://test.example.com/tag"></iframe>
Why it matters
noscript is where tag managers, analytics fallbacks and tracking pixels put their markup, so the bypass covers the requests a trusted server exists to carry. It fails silently. The page renders correctly and nothing is logged.
Cause
lol_html classifies noscript as raw text rather than markup, unconditionally and alongside style and iframe. The content therefore never becomes elements, so no attribute handler can see inside it. This is in the parser's tree builder simulator rather than in Trusted Server, so registering another element handler cannot reach it.
How it was reproduced
By adding a test to your own html_processor suite at 0f8b44dc0, using the existing create_test_config harness, and running the document above through StreamingPipeline. The output above is what the test observed. One of the two identical URLs was rewritten.
Suggested fix
Register a text!("noscript", ...) handler. A text node arrives in chunks and a URL can straddle two of them, so the node has to be accumulated and rewritten once complete, with earlier chunks held back rather than emitted, or the content is duplicated. The result must be emitted as HTML rather than as text, because it is markup the parser merely declined to parse, and escaping it would show the visitor the tags.
A branch is ready at fix/noscript-bypass, with a test covering both the rewriting and the escaping. It merges cleanly against main.
One dependency worth flagging. It sits on top of fix/origin-host-boundary, the branch offered for #1119, because both change the same rewriting path. Taking the boundary fix first makes this one a single commit.
Written with AI assistance and checked against the source at 0f8b44dc0. Worth a human review before acting on it.
Every URL inside a
<noscript>element reaches the visitor unrewritten. The proxy never sees it, so the browser contacts the third party directly.The same URL inside and outside a
noscriptis treated differently. This input:comes back as:
Why it matters
noscriptis where tag managers, analytics fallbacks and tracking pixels put their markup, so the bypass covers the requests a trusted server exists to carry. It fails silently. The page renders correctly and nothing is logged.Cause
lol_htmlclassifiesnoscriptas raw text rather than markup, unconditionally and alongsidestyleandiframe. The content therefore never becomes elements, so no attribute handler can see inside it. This is in the parser's tree builder simulator rather than in Trusted Server, so registering another element handler cannot reach it.How it was reproduced
By adding a test to your own
html_processorsuite at0f8b44dc0, using the existingcreate_test_configharness, and running the document above throughStreamingPipeline. The output above is what the test observed. One of the two identical URLs was rewritten.Suggested fix
Register a
text!("noscript", ...)handler. A text node arrives in chunks and a URL can straddle two of them, so the node has to be accumulated and rewritten once complete, with earlier chunks held back rather than emitted, or the content is duplicated. The result must be emitted as HTML rather than as text, because it is markup the parser merely declined to parse, and escaping it would show the visitor the tags.A branch is ready at
fix/noscript-bypass, with a test covering both the rewriting and the escaping. It merges cleanly againstmain.One dependency worth flagging. It sits on top of
fix/origin-host-boundary, the branch offered for #1119, because both change the same rewriting path. Taking the boundary fix first makes this one a single commit.Written with AI assistance and checked against the source at
0f8b44dc0. Worth a human review before acting on it.