fix(core): sanitize sensitive attributes on SVG script elements

This commit updates the DOM security schema and sanitization logic to properly recognize and sanitize `href` and `xlink:href` attributes on SVG `<script>` elements.
This commit is contained in:
Alan Agius 2026-01-06 21:54:47 +01:00 committed by GitHub
parent 4755bbd949
commit c2c2b4aaa8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 44 additions and 12 deletions

View file

@ -8530,6 +8530,34 @@ runInEachFileSystem((os: string) => {
expect(trim(jsContents)).toContain(trim(hostBindingsFn));
});
it('should generate sanitizers for URL properties in SVG script fn in Component', () => {
env.write(
'test.ts',
`
import {Component} from '@angular/core';
@Component({
selector: 'test-cmp',
template: \`
<svg>
<script [attr.xlink:href]="attr" [attr.href]="attr"></script>
</svg>
\`,
})
export class TestCmp {
attr = './script.js';
}
`,
);
env.driveMain();
const jsContents = env.getContents('test.js');
expect(jsContents).toContain(
'i0.ɵɵattribute("href", ctx.attr, i0.ɵɵsanitizeResourceUrl, "xlink")("href", ctx.attr, i0.ɵɵsanitizeResourceUrl);',
);
});
it('should not generate sanitizers for URL properties in hostBindings fn in Component', () => {
env.write(
`test.ts`,

View file

@ -134,6 +134,10 @@ export function SECURITY_SCHEMA(): {[k: string]: SecurityContext} {
'object|codebase',
'object|data',
'script|src',
// The below two are for Script SVG
// See: https://developer.mozilla.org/en-US/docs/Web/API/SVGScriptElement/href
'script|href',
'script|xlink:href',
]);
// Keep this in sync with SECURITY_SENSITIVE_ELEMENTS in packages/core/src/sanitization/sanitization.ts

View file

@ -213,6 +213,10 @@ export function ɵɵtrustConstantResourceUrl(url: TemplateStringsArray): Trusted
return trustedScriptURLFromString(url[0]);
}
// Define sets outside the function for O(1) lookups and memory efficiency
const SRC_RESOURCE_TAGS = new Set(['embed', 'frame', 'iframe', 'media', 'script']);
const HREF_RESOURCE_TAGS = new Set(['base', 'link', 'script']);
/**
* Detects which sanitizer to use for URL property, based on tag name and prop name.
*
@ -221,18 +225,12 @@ export function ɵɵtrustConstantResourceUrl(url: TemplateStringsArray): Trusted
* If tag and prop names don't match Resource URL schema, use URL sanitizer.
*/
export function getUrlSanitizer(tag: string, prop: string) {
if (
(prop === 'src' &&
(tag === 'embed' ||
tag === 'frame' ||
tag === 'iframe' ||
tag === 'media' ||
tag === 'script')) ||
(prop === 'href' && (tag === 'base' || tag === 'link'))
) {
return ɵɵsanitizeResourceUrl;
}
return ɵɵsanitizeUrl;
const isResource =
(prop === 'src' && SRC_RESOURCE_TAGS.has(tag)) ||
(prop === 'href' && HREF_RESOURCE_TAGS.has(tag)) ||
(prop === 'xlink:href' && tag === 'script');
return isResource ? ɵɵsanitizeResourceUrl : ɵɵsanitizeUrl;
}
/**

View file

@ -115,6 +115,7 @@
"HOST",
"HOST_ATTR",
"HOST_TAG_NAME",
"HREF_RESOURCE_TAGS",
"HYDRATION",
"HistoryStateManager",
"HostAttributeToken",
@ -274,6 +275,7 @@
"SIGNAL",
"SIGNAL_NODE",
"SIMPLE_CHANGES_STORE",
"SRC_RESOURCE_TAGS",
"SVG_NAMESPACE",
"SafeSubscriber",
"SafeValueImpl",