From 4fd8f61c0fa255a348d2628bc8a8647fa5245f6f Mon Sep 17 00:00:00 2001
From: SkyZeroZx <73321943+SkyZeroZx@users.noreply.github.com>
Date: Fri, 10 Jul 2026 17:00:07 -0500
Subject: [PATCH] fix(@angular/build): prevent HTML injection from inlined font
CSS
Remote font CSS is embedded into a raw-text style element. Escape closing style tags so a compromised allowlisted response cannot terminate the style element and inject nonce-bearing markup.
---
.../src/utils/index-file/inline-fonts.ts | 5 ++--
.../src/utils/index-file/inline-fonts_spec.ts | 28 +++++++++++++++++++
2 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/packages/angular/build/src/utils/index-file/inline-fonts.ts b/packages/angular/build/src/utils/index-file/inline-fonts.ts
index 52181200c885..c4bdc18af7af 100644
--- a/packages/angular/build/src/utils/index-file/inline-fonts.ts
+++ b/packages/angular/build/src/utils/index-file/inline-fonts.ts
@@ -150,8 +150,9 @@ export class InlineFontsProcessor {
attrs.find(({ name, value }) => name === 'href' && hrefsContent.has(value));
if (hrefAttr) {
const href = hrefAttr.value;
- const cssContent = hrefsContent.get(href);
- rewriter.emitRaw(``);
+ const cssContent = hrefsContent.get(href) ?? '';
+ // Prevent the CSS from terminating the generated raw-text style element.
+ rewriter.emitRaw(``);
} else {
rewriter.emitStartTag(tag);
}
diff --git a/packages/angular/build/src/utils/index-file/inline-fonts_spec.ts b/packages/angular/build/src/utils/index-file/inline-fonts_spec.ts
index 46511f853ecf..ad1aea3c8830 100644
--- a/packages/angular/build/src/utils/index-file/inline-fonts_spec.ts
+++ b/packages/angular/build/src/utils/index-file/inline-fonts_spec.ts
@@ -6,7 +6,9 @@
* found in the LICENSE file at https://angular.dev/license
*/
+import { htmlRewritingStream } from './html-rewriting-stream';
import { InlineFontsProcessor } from './inline-fonts';
+import { addNonce } from './nonce';
describe('InlineFontsProcessor', () => {
describe('Google fonts', () => {
@@ -100,6 +102,32 @@ describe('InlineFontsProcessor', () => {
``,
);
});
+
+ it('should escape closing style tags in inlined CSS', async () => {
+ const inlineFontsProcessor = new InlineFontsProcessor({
+ minify: true,
+ });
+ spyOn(inlineFontsProcessor, 'processURL').and.resolveTo(
+ 'body { color: red; }