When a class name is derived from user-controlled or backend-driven data (e.g. a CMS field or query parameter forwarded into a `theme` input), binding it directly via `[class]="userValue"` lets an attacker inject arbitrary class names that may collide with unrelated selectors elsewhere in the app, or — combined with a loose global stylesheet — be leveraged for CSS-based data exfiltration (attribute selectors that trigger background-image requests). Angular does not sanitize class bindings the way it sanitizes `innerHTML` or `href`, because a class name isn't inherently active content, so the allowlist check here is the actual security boundary, not a redundant one.
const ALLOWED_THEME_CLASSES = new Set(['theme-default', 'theme-compact', 'theme-highcontrast']);@Component({selector: 'app-themed-card',standalone: true,template: `<div [class]="resolvedClass()"><ng-content /></div>`,})export class ThemedCardComponent {readonly themeInput = input<string>('theme-default', { alias: 'theme' });readonly resolvedClass = computed(() => {const requested = this.themeInput().trim();if (!ALLOWED_THEME_CLASSES.has(requested)) {console.warn(`Rejected unrecognized theme class "${requested}"; falling back to default.`);return 'theme-default';}return requested;});}