diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
index c3af979eb74a..5938c0a3ad59 100644
--- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
+++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
@@ -8595,7 +8595,7 @@ runInEachFileSystem((os: string) => {
hostVars: 6,
hostBindings: function UnsafeAttrsDirective_HostBindings(rf, ctx) {
if (rf & 2) {
- i0.ɵɵattribute("href", ctx.attrHref, i0.ɵɵsanitizeUrlOrResourceUrl)("src", ctx.attrSrc, i0.ɵɵsanitizeUrlOrResourceUrl)("action", ctx.attrAction, i0.ɵɵsanitizeUrl)("profile", ctx.attrProfile)("innerHTML", ctx.attrInnerHTML, i0.ɵɵsanitizeHtml)("title", ctx.attrSafeTitle);
+ i0.ɵɵattribute("href", ctx.attrHref, i0.ɵɵsanitizeUrlOrResourceUrl)("src", ctx.attrSrc, i0.ɵɵsanitizeUrlOrResourceUrl)("action", ctx.attrAction, i0.ɵɵsanitizeUrl)("profile", ctx.attrProfile)("innerHTML", ctx.attrInnerHTML, i0.ɵɵsanitizeMaybeScript)("title", ctx.attrSafeTitle);
}
}
`;
diff --git a/packages/compiler/src/render3/r3_identifiers.ts b/packages/compiler/src/render3/r3_identifiers.ts
index 82d96103762f..a7c6a9492021 100644
--- a/packages/compiler/src/render3/r3_identifiers.ts
+++ b/packages/compiler/src/render3/r3_identifiers.ts
@@ -477,6 +477,10 @@ export class Identifiers {
name: 'ɵɵsanitizeUrlOrResourceUrl',
moduleName: CORE,
};
+ static sanitizeMaybeScript: o.ExternalReference = {
+ name: 'ɵɵsanitizeMaybeScript',
+ moduleName: CORE,
+ };
static trustConstantHtml: o.ExternalReference = {name: 'ɵɵtrustConstantHtml', moduleName: CORE};
static trustConstantResourceUrl: o.ExternalReference = {
name: 'ɵɵtrustConstantResourceUrl',
diff --git a/packages/compiler/src/schema/dom_security_schema.ts b/packages/compiler/src/schema/dom_security_schema.ts
index 26a4f8bf16a9..8d0da48ec275 100644
--- a/packages/compiler/src/schema/dom_security_schema.ts
+++ b/packages/compiler/src/schema/dom_security_schema.ts
@@ -28,7 +28,18 @@ export function SECURITY_SCHEMA(): {[k: string]: SecurityContext} {
registerContext(SecurityContext.HTML, ['iframe|srcdoc', '*|innerHTML', '*|outerHTML']);
registerContext(SecurityContext.STYLE, ['*|style']);
- // NB: no SCRIPT contexts here, they are never allowed due to the parser stripping them.
+ // Writes to text-like properties of a ``,
+ changeDetection: ChangeDetectionStrategy.Eager,
+ })
+ class TestCmp {
+ code = '/* xss */';
+ }
+
+ expect(() => {
+ const fixture = TestBed.createComponent(TestCmp);
+ fixture.detectChanges();
+ }).toThrowError(/NG0905/);
+ });
+
+ it(`should error when '${propName}' is bound on an SVG ',
+ imports: [ScriptHostDir],
+ changeDetection: ChangeDetectionStrategy.Eager,
+ })
+ class TestCmp {}
+
+ expect(() => {
+ const fixture = TestBed.createComponent(TestCmp);
+ fixture.detectChanges();
+ }).toThrowError(/NG0905/);
+ });
+ }
+
+ it('should allow values trusted via DomSanitizer.bypassSecurityTrustScript', () => {
+ @Component({
+ template: '',
+ changeDetection: ChangeDetectionStrategy.Eager,
+ })
+ class TestCmp {
+ private readonly sanitizer = inject(DomSanitizer);
+ code = this.sanitizer.bypassSecurityTrustScript('/* trusted */');
+ }
+
+ const fixture = TestBed.createComponent(TestCmp);
+ fixture.detectChanges();
+ expect(fixture.nativeElement.querySelector('script').textContent).toContain('/* trusted */');
+ });
+});
diff --git a/packages/core/test/sanitization/sanitization_spec.ts b/packages/core/test/sanitization/sanitization_spec.ts
index bdfbc3882666..8e8243bc0f53 100644
--- a/packages/core/test/sanitization/sanitization_spec.ts
+++ b/packages/core/test/sanitization/sanitization_spec.ts
@@ -118,7 +118,7 @@ describe('sanitization', () => {
[SecurityContext.RESOURCE_URL, ɵɵsanitizeResourceUrl],
]);
Object.entries(schema).forEach(([key, context]) => {
- if (context === SecurityContext.URL || SecurityContext.RESOURCE_URL) {
+ if (context === SecurityContext.URL || context === SecurityContext.RESOURCE_URL) {
const [tag, prop] = key.split('|');
const contexts = contextsByProp.get(prop) || new Set();
contexts.add(context);