Skip to content

fix(security): align SVG, i18n, and host-binding sinks with Angular v22 - #334

Merged
Brooooooklyn merged 15 commits into
mainfrom
fix/issue-315-security-contexts
Sep 22, 2026
Merged

Brooooooklyn merged 15 commits into
mainfrom
fix/issue-315-security-contexts

Conversation

@Brooooooklyn

@Brooooooklyn Brooooooklyn commented Jun 2, 2026

Copy link
Copy Markdown
Member

Summary

Closes #315.

main vendors @angular/compiler v22.0.0. Passing no version, or v22+, uses that schema. Passing an earlier angularVersion keeps the schema that release actually shipped, so a v21 build does not pick up v22-only namespaced keys.

Target Security lookup
before 21.1 Bare keys. script|src is a resource URL. No SVG animation sinks.
21.1 – 21.2.6 Also script|href, MathML href, and attributeName no-binding.
21.2.4+ i18n rejects iframe|src.
21.2.7 – 21.x Also bare animate/set to, from, and values. :svg:animate|to does not match. :svg:script is kept.
22+ (default) Keys keep :svg: and :math:. script|src is gone. :svg:script is stripped. ATTRIBUTE_NO_BINDING emits ɵɵvalidateAttribute.

Host bindings use the same version: v22 promotes a bare selector element to :svg: / :math: and lowercases :not(). v21 matches the element string as written.

Validation

  • cargo test -p oxc_angular_compiler
  • cargo run -p oxc_angular_conformance: 1264/1264 (default schema is v22)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a2806b8621

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
@cursor

cursor Bot commented Aug 11, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_759d00f2-30f8-4a36-a6bf-f592d036fdac)

@cursor

cursor Bot commented Aug 11, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_346b568d-16dc-4542-b4d4-c30da0af2790)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 626d83bc9f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
Issue #315 is still open on main, which vendors @angular/compiler v22.0.0.
The previous branch pinned v21.2.7 and stripped namespaces before lookup.
v22 keeps :svg: and :math: in the security key and strips script elements
instead of treating script|src as a resource URL.

- Register the v22 DOM security schema, including SVG animation attributes
  as ATTRIBUTE_NO_BINDING and namespaced MathML hrefs.
- Compute host-binding security from the directive selector, including
  :not() and svg/math promotion of unknown element names.
- Map ATTRIBUTE_NO_BINDING to ɵɵvalidateAttribute.
- Reject i18n of Trusted Types sinks without stripping a namespace prefix.
- Drop script and :svg:script while lowering templates, and look security
  up on the qualified element name.
@Brooooooklyn
Brooooooklyn force-pushed the fix/issue-315-security-contexts branch from 626d83b to d80213b Compare September 22, 2026 02:12
@Brooooooklyn Brooooooklyn changed the title fix(security): close SVG/i18n security-context gaps vs @angular/compiler v21.2.7 fix(security): align SVG, i18n, and host-binding sinks with Angular v22 Sep 22, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 22, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-22T16:34:38.278227Z f103a7f New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d80213b53a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/i18n/extractor_merger.rs Outdated
Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
v22 stays the default. Compiling for an earlier version uses that
version's security schema instead of the namespaced v22 keys.

- Before 21.1: script|src only.
- 21.1 through 21.2.6: script|href, MathML hrefs, attributeName no-binding.
- 21.2.4+: i18n rejects iframe|src.
- 21.2.7 through 21.x: bare animate/set to, from, and values.
- 22+: namespaced keys, and :svg:script is stripped.
Trusted Types compares the parser's full element name and does not
drop a non-svg/math prefix. Script stripping matches only `script`
and `:svg:script`. Implicit i18n attributes that name a sink are
rejected on extract and merge, same as an explicit i18n-* marker.
Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a55970ea14

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
`<MyComp:iframe i18n-src>` was matched as the class name. Trusted Types
now uses the host tag, including an explicit namespace. A component with
no host tag is not a sink. Real `<script>` and `<style>` elements are
still stripped.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b25c6409b1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs
Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs
A selectorless component inside `<svg>` or `<math>` takes that namespace,
the same way Angular builds `tagName`. `<svg><MyComp i18n-innerHTML>` is
`:svg:ng-component` and is rejected. `<svg><MyComp:iframe i18n-src>` is
`:svg:iframe` and is not the `iframe|src` sink. `foreignObject` still
resets the namespace to HTML.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 933649f7f7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/schema/dom_security_schema.rs Outdated
Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d6bf367e01

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
Comment thread crates/oxc_angular_compiler/src/schema/dom_security_schema.rs
@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d6bf367e01

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
Comment thread crates/oxc_angular_compiler/src/schema/dom_security_schema.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8fab161c64

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs Outdated
Upstream backported the security-schema fixes non-monotonically, so a flat
major/minor gate mis-assigns keys on several versions:

- 21.0.6 dropped the legacy ping/cite/applet/media keys before script|href
  landed in 21.0.7, so it needs its own profile.
- 20.3.16-20.3.21 keep the legacy URL keys alongside script|href; the key
  removal was never backported to the 20.3 line.
- 21.2.14 is namespaced but lacks :svg:a|href (added in 20.3.22 / 21.2.15).
- The preparser classified :svg:style as a style element only on 20.3.22
  and 21.2.14 (STYLE_ELEMENTS); it was reverted everywhere else.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ee63c9e9f6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs
Upstream _getPrefix passes getNsPrefix(parentName) to children verbatim,
so a parent like :xml:div resolves its children to :xml:* and normalizeTagName
then drops the non-svg/math prefix for the security lookup. The previous
ElementNamespace stack could only represent svg/math/html, so an arbitrary
prefix fell back to the surrounding namespace and <svg><xml:div><iframe [src]>
was treated as :svg:iframe, losing the iframe|src sanitizer.

The stack now stores the inheritable prefix string. resolve_element_name
reproduces mergeNsAndName(_getPrefix()) for element names, emitted tag names,
selectorless host tags, and isVoid lookups, while security_lookup_name applies
normalizeTagName to the resolved name.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0324bb1a9f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/transform/html_to_r3.rs
calcPossibleSecurityContexts only promotes an unknown bare selector to
:svg:/:math: form on the namespaced schema (20.3.22+, 21.2.14+, v22).
Promoting unconditionally made <MyComp:animate [attr.to]> miss the bare
animate|to key on 21.2.7-21.2.13, dropping ɵɵvalidateAttribute. Gate the
promotion on the schema kind; host tags pass through verbatim on earlier
versions, matching upstream.
The 19.2 release line received the same security backports as 20.3/21.x,
but every 19.x target fell through to the legacy schema:

- 19.2.17 hardened (MathML hrefs, a|xlink:href, attributeNoBinding)
  while keeping the legacy URL keys
- 19.2.18-19.2.22 added script|href; iframe|src joined the Trusted
  Types sinks at 19.2.20
- 19.2.23+ has the namespaced schema including :svg:a|href, and 19.2.23
  is the only 19.x tag where the preparser strips :svg:style
Upstream resolve_sanitizers.ts falls back to ɵɵvalidateIframeAttribute
when a Property/Attribute/DomProperty op on an iframe got no sanitizer
from its security context. The path exists on versions without the
iframe attributeNoBinding schema keys (removed upstream in 19.2.17 /
20.3.15 / 21.0.2), so gate it to the legacy schema.

Also pass angular_version into TransformOptions in the integration test
helper so version-targeted tests compile templates against the matching
security schema.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5150f3ab6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/i18n/extractor_merger.rs Outdated
Upstream added `normalizeTagName` to `securityContext` one release after
the namespaced schema keys: 19.2.23, 20.3.22, and 21.2.15. At 21.2.14
(and every earlier version) the tag is lowercased verbatim, so
`:xml:iframe|src` misses the schema and produces no sanitizer. Our lookup
stripped the prefix unconditionally, emitting `ɵɵsanitizeResourceUrl`
for targets where upstream assigns NONE.

`get_security_context_for` now takes the verbatim resolved name and a new
`normalizes_tag_names` profile flag (the V22 schema kind) decides whether
`normalizeTagName` applies.
@Brooooooklyn

Copy link
Copy Markdown
Member Author

Round of fixes against upstream tags landed:

82c7bea — 19.2.x schema cutovers. The 19.2 line got the same backports as 20.3/21.x but every 19.x target fell through to the legacy schema. Verified per tag: 19.2.17 hardened (MathML hrefs, a|xlink:href, attributeNoBinding) with legacy keys; v19.2.18v19.2.22 add script|href (iframe|src joins the Trusted Types sinks at v19.2.20); v19.2.23+ is the namespaced schema including :svg:a|href. :svg:style stripping is exactly 19.2.23 / 20.3.22 / 21.2.14.

f5150f3 — legacy ɵɵvalidateIframeAttribute. Upstream resolve_sanitizers.ts (present since at least 18.2.13) falls back to ɵɵvalidateIframeAttribute when a Property/Attribute/DomProperty on an iframe got no sanitizer — host jobs and DomProperty assume iframe, otherwise the owner op's ElementStart tag is checked (IFRAME_SECURITY_SENSITIVE_ATTRS = sandbox/allow/allowfullscreen/referrerpolicy/csp/fetchpriority, lowercase compare). Removed upstream once the schema's iframe attributeNoBinding keys landed (19.2.17 / 20.3.15 / 21.0.2), so it's gated to the legacy schema.

da571canormalizeTagName version gating. securityContext only normalizes the tag at 19.2.23 / 20.3.22 / 21.2.15+; 21.2.14 has the namespaced schema keys but lowercases the tag verbatim. :xml:iframe|src now produces NONE at 21.2.14 (matching upstream) and ResourceUrl at 21.2.15+.

Verified against the vendored v22 sources plus raw.githubusercontent.com tags for the boundary releases. 1119 lib + 434 integration tests green, conformance 1264/1264 with unchanged snapshot.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da571ca492

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/schema/dom_security_schema.rs Outdated
`extract_messages`/`merge_translations` hard-coded the v22 sink list via
`is_trusted_types_sink`, so a 21.2.3 target that compiles `iframe i18n-src`
fine was still rejected during extraction. Both APIs now take the target
Angular version and the visitor uses `is_trusted_types_sink_at`, keeping
extraction, merge, and template compilation on the same 21.2.4 cutoff.
Upstream's selector regexp has no `*` production, so `CssSelector.parse`
leaves `element` unset for `*` and `*[x]`, and `calcPossibleSecurityContexts`
expands them over all known element names. Our parser set `element` to `*`,
so a directive like `*[feature]` with a `src` host binding only hit the
`*|src` schema key and got no sanitizer instead of `sanitizeUrlOrResourceUrl`.

The one place upstream keeps a literal `*` element is a `:not(...)`-only
selector; it looks up the `*|attr` key verbatim there, so the expansion in
`collect_namespaced_contexts` is removed to match.
@Brooooooklyn

Copy link
Copy Markdown
Member Author

Latest round of fixes against upstream tags landed:

f103a7f — universal-selector host security. Our CssSelector parser set element = "*" for a literal * token. Upstream _SELECTOR_REGEXP has no * production, so element stays unset and calcPossibleSecurityContexts expands over allKnownElementNames()* / *[attr] + [src] now resolves to sanitizeUrlOrResourceUrl like upstream, in both the namespaced and bare-schema paths. The element = '*' literal is preserved only for the upstream :not(...)-only-selector hack (*:not(img), :not(img):not(video)), which upstream does NOT expand — it does a literal *|prop lookup. resolve_concrete_element's * expansion was removed to match.

All threads resolved; every finding so far verified against vendored @angular/compiler v22.0.0 and the corresponding upstream release tags. Suite: 1121 lib tests, 434 integration tests, 1264/1264 conformance cases green.

@Brooooooklyn
Brooooooklyn merged commit 943a5b6 into main Sep 22, 2026
10 checks passed
@Brooooooklyn
Brooooooklyn deleted the fix/issue-315-security-contexts branch September 22, 2026 16:53
@Brooooooklyn

Copy link
Copy Markdown
Member Author

Post-merge adversarial review verified against upstream tags. One finding was a real divergence from the v22.0.0 baseline: element bindings skipped the unknown-element :svg:/:math: promotion inside calcPossibleSecurityContexts, so <animate [attr.to]> missed ɵɵvalidateAttribute. Fixed in #490 (also fixes the bare-schema path not re-applying the selector's :ns: prefix, matching upstream nameToContext).

All other findings describe upstream behavior that landed after our vendored v22.0.0 and don't apply to this baseline: credentialless iframe sink + namespaced→default fallback (22.0.2), MathML *|href wildcard (22.0.1), calcHostBindingSecurityContexts concrete-host scan (22.1.0), i18n on* rejection (22.1.0), :math:script stripping (22.1.2), bare→svg fallback in checkSecurityContext (22.1.5). Tracking those would need finer-grained angular_version gating — separate decision.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security: missing security-context entries for SVG animation, iframe i18n, and namespaced SVG script elements

1 participant