fix(security): close SVG/i18n security-context gaps vs @angular/compiler v21.2.7 - #334
fix(security): close SVG/i18n security-context gaps vs @angular/compiler v21.2.7#334Brooooooklyn wants to merge 5 commits into
Conversation
Regenerate the conformance fixtures and angular.snap.md against the vendored Angular v21.2.7 submodule so `cargo run -p oxc_angular_conformance` is idempotent (git diff --exit-code clean). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ler v21.2.7 (#315) Bump the vendored @angular/compiler submodule to v21.2.7 and port the security-context fixes from issue #315, keeping oxc_angular_compiler a faithful 1:1 reimplementation of the pinned upstream. Issue #315 sub-gaps: - Host bindings now compute the security context (multi-selector union/merge plus case-sensitive :not(element) exclusions over allKnownElementNames). - AOT i18n: trusted-types sink attributes (e.g. iframe|src) are rejected for translation; the guard uses the resolved element tag. - Template preparser strips :svg:script (in addition to script), matching v21.2.7 SCRIPT_ELEMENTS. Faithfulness fixes surfaced during 22 adversarial-review iterations: - Namespaced security lookup: :svg:/:math: elements resolve by local name; the host-unknown scan skips the full phantom set of SECURITY_SCHEMA element segments that exist only namespaced (:svg:animate, :math:*) or are absent from the element schema, so it matches upstream allKnownElementNames reachability (no over-validation, no under-sanitization). - SVG/MathML namespace inheritance for implicit and selectorless children; namespaced raw-text and namespaced void-local close-tag handling. - Explicit parser is_component marker (uppercase element vs bare component) threaded through security, i18n, and AST construction. - Namespaced attribute codegen (mergeNsAndName) for template attr bindings; host bindings left unsplit, matching upstream. - ShadowCss: closed-comment-only handling, ECMAScript \s semantics, unanchored sourceURL detection, single-pass comment restore, and a scoping-leak fix. Validation: cargo fmt/check clean; full Rust test suite passes (0 failed, 1 pre-existing ignored); conformance 1259/1259 (100%, idempotent). The final adversarial review returned an approved verdict with no material findings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 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".
Signed-off-by: Brandon Roberts <robertsbt@gmail.com>
Merge origin/main into fix/issue-315-security-contexts and address Codex review on html_to_r3 visit_element: - Read element.is_component before special script/style/link handling - Skip preparser Element-only filtering for selectorless components (matches upstream visitComponent, which never calls preparseElement) - Keep UNSUPPORTED_SELECTORLESS_TAGS check on resolved host tag - Add unit tests for bare <Script>/<Style>/<Link/> components vs real lowercase <script>/<style> elements Merge notes: - Keep PR angular submodule pin at v21.2.7 - Prefer PR security-context / is_component / namespaced semantics - Prefer main relative fixture paths; oxfmt fixtures after merge - Fix Vec::new_in(&allocator) API after oxc 0.140 merge
Bugbot couldn't run - usage limit reachedBugbot 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) |
Merge from main pulled v22 semantics that break the v21.2.7 pin for #315: - restore case-insensitive data- attribute name normalization for bindings - strip trailing semicolon from @let humanized source spans (v21 fixtures) - fix shadow_css comment fixtures that mixed {} input with {c} expected Conformance: 1273/1273 (100%).
Bugbot couldn't run - usage limit reachedBugbot 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) |
There was a problem hiding this comment.
💡 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".
| /// prefix is no longer stripped, so `data-on-x` is not an event binding. | ||
| /// Matches TypeScript v21.2.7: `/^data-/i.test(attrName) ? attrName.substring(5) : attrName`. | ||
| fn normalize_attribute_name<'b>(&self, name: &'b str) -> &'b str { | ||
| if name.len() > 5 && name[..5].eq_ignore_ascii_case("data-") { &name[5..] } else { name } |
There was a problem hiding this comment.
Avoid slicing Unicode attribute names by byte offset
When an attribute name contains multibyte characters and byte offset 5 is not a UTF-8 boundary, this indexing panics before the prefix comparison; for example, the permissive HTML lexer accepts <div ééé="x"></div>, but ééé has six bytes and name[..5] splits the final character, crashing the compiler during the R3 transform. Check the ASCII data- prefix through a boundary-safe operation such as name.get(..5) before slicing.
Useful? React with 👍 / 👎.
Summary
Closes #315.
Bumps the vendored
@angular/compilersubmodule to v21.2.7 and ports the security-context fixes from issue #315, keepingoxc_angular_compilera faithful 1:1 reimplementation of the pinned upstream.Issue #315 sub-gaps
:not(element)exclusions overallKnownElementNames).iframe|src) for translation; the guard uses the resolved element tag.:svg:script(in addition toscript), matching v21.2.7SCRIPT_ELEMENTS.Faithfulness fixes surfaced during review
:svg:/:math:elements resolve by local name; the host-unknown scan skips the full phantom set ofSECURITY_SCHEMAelement segments that exist only namespaced (:svg:animate,:math:*) or are absent from the element schema, so it matches upstreamallKnownElementNamesreachability — no over-validation, no under-sanitization (verified: phantom set == {sec segments} − {bare known} exactly).is_componentmarker (uppercase element vs bare component) threaded through security, i18n, and AST construction.mergeNsAndName) for template attr bindings; host bindings left unsplit, matching upstream.\ssemantics, unanchored sourceURL detection, single-pass restore, and a scoping-leak fix.Validation
cargo fmt --all -- --check: clean ·cargo check: 0 errorscargo test -p oxc_angular_compiler: all binaries pass (0 failed, 1 pre-existing ignored)cargo run -p oxc_angular_conformance: 1259/1259 (100%), idempotent🤖 Generated with Claude Code
Note
High Risk
Touches authentication-adjacent security context, i18n XSS guards, and core HTML/R3 parsing paths; incorrect namespace or sink handling could change sanitization or template output.
Overview
Aligns oxc_angular_compiler with @angular/compiler v21.2.7 for issue #315 and related parser/i18n faithfulness gaps.
Security & sanitization: Host bindings on components/directives now get real
security_contextviahost_binding_security_contextinstead ofNone.ATTRIBUTE_NO_BINDINGbindings map toɵɵvalidateAttributeinresolve_sanitizers. i18n extraction/merge blocks trusted-types sink attributes without stripping namespace prefixes (e.g.:svg:iframe|srcstays allowed).HTML lexer/parser: Adds
@default never;exhaustive switch (BlockType::DefaultNever), digit-named entities, andIncompleteBlockOpenhandling. Namespace inheritance and component open/close matching use resolved full names;HtmlElementgainsis_component. Raw-text scanning is unified (local vs component close boundaries); default mode treats<_foo>as text while selectorless mode differs for top-level vs mid-text<_.R3 / i18n:
R3SwitchExhaustiveCheckdrops optional expression; conformance humanizer trims@letspan semicolons for v21.2.7. Selectorless components usefullName/void host tags in i18n placeholders. Binding specialization uses sharedsplit_ns_namefrom the HTML tags module.Conformance: Fixture JSON updates (entities, switch blocks, R3 spans for
data-*bindings, ShadowCss comments) and snapshot totals 1273 tests at 100% pass.Reviewed by Cursor Bugbot for commit 626d83b. Bugbot is set up for automated code reviews on this repo. Configure here.