When you enforce Trusted Types on an Angular app, which Angular policy names must the trusted-types directive allow, and what breaks if one is missing?
answer
- one required, four conditional
- sanitized values versus bypassed values
- lazy chunks from the bundler
- policy creation fails quietly
- the sink assignment then throws
basics
~10 sThe angular policy is always required; angular#unsafe-bypass is needed for bypassSecurityTrust methods, angular#bundler for CLI lazy chunks, angular#unsafe-jit for JIT and angular#unsafe-upgrade for AngularJS hybrids. Without one, that feature's DOM writes fail as violations.
solid answer
~40 sTrusted Types enforcement, `require-trusted-types-for 'script'`, makes the browser reject plain strings at sinks such as `innerHTML` and script URLs, and the `trusted-types` directive lists which named policies may create trusted values. Angular uses five names. `angular` wraps values Angular has already sanitized and trusted template constants, and is always required. `angular#unsafe-bypass` wraps values from `DomSanitizer.bypassSecurityTrust*`. `angular#bundler` is used by the CLI bundler for lazy chunk files, `angular#unsafe-jit` by the JIT compiler, and `angular#unsafe-upgrade` by `@angular/upgrade`. When a name is not allowed, Angular catches the policy-creation error and falls back to plain strings, so nothing fails at startup; the failure comes later, when that feature writes to a sink and the browser throws. The `unsafe` names mark features worth removing rather than allowing.
go deeper
Recall that Angular ships named Trusted Types policies and that the angular policy is always required under enforcement.
Map each policy to its feature: bypass methods, CLI lazy chunks, JIT and AngularJS upgrade.
Diagnose a violation back to the missing policy, knowing that failure appears at the sink rather than at bootstrap, and prefer removing unsafe features over allowing their policies.
Decide whether the organisation enforces Trusted Types, how third-party libraries are handled, and who approves any unsafe policy in the header.
## What enforcement changes **Trusted Types** is a browser feature switched on through CSP. Two directives matter: - `require-trusted-types-for 'script'` makes injection sinks, such as `innerHTML`, `srcdoc`, script `src` and `eval`, **reject plain strings**. They accept only typed objects such as `TrustedHTML`. - `trusted-types <names>` lists the **policies** allowed to create those objects. A policy is a named factory created with `trustedTypes.createPolicy(name, rules)`. Angular's own DOM writes therefore have to pass typed values, and it creates them through a small set of named policies. The browser API itself is a platform subject; what an Angular interview asks is **which names Angular uses and what each one covers**. ## Angular's policies | Policy | Used for | Allow it when | | :--- | :--- | :--- | | `angular` | values Angular has sanitized, and constant values from templates | always: Angular needs it to function under enforcement | | `angular#unsafe-bypass` | values wrapped by `bypassSecurityTrustHtml`, `bypassSecurityTrustScript` and `bypassSecurityTrustResourceUrl` | the app calls any `DomSanitizer` bypass method | | `angular#bundler` | the Angular CLI bundler when it creates lazy chunk files | the app lazy-loads code | | `angular#unsafe-jit` | the JIT compiler turning generated source into functions | the app runs in JIT mode or uses the runtime compiler | | `angular#unsafe-upgrade` | the `@angular/upgrade` package | the app is an AngularJS hybrid | A typical header for an AOT app with lazy routes and no bypasses: ```txt Content-Security-Policy: trusted-types angular angular#bundler; require-trusted-types-for 'script'; ``` The `#unsafe` suffix is a review signal. Values created through `angular#unsafe-bypass` are exactly the ones Angular did **not** sanitize, so listing that policy is an admission that some part of the app trusts unchecked strings. The same goes for JIT, which turns strings into code. ## What a missing policy looks like Angular creates each policy lazily, the first time a feature needs it. If the name is not in `trusted-types`, `createPolicy` throws, and Angular **catches** the error and falls back to plain strings. Nothing breaks at bootstrap. The breakage appears later: 1. A component binds a `SafeHtml` created by `bypassSecurityTrustHtml` to `[innerHTML]`. 2. Angular tries to wrap it through `angular#unsafe-bypass`, cannot, and passes a plain string. 3. The browser rejects the string at the `innerHTML` sink and reports a Trusted Types violation; that content never renders. Sanitized `[innerHTML]` values in the same app keep working, because they go through `angular`. That split, where only the bypassed content fails, is the usual clue to which policy is missing. ## What enforcement buys an Angular app - **Direct DOM writes fail loudly.** `nativeElement.innerHTML = value` or a third-party widget assigning a plain string now throws instead of silently creating markup. This is the protection the sanitizer cannot give, because it lives only in compiled bindings. - **An audit trail of trust.** Every trusted value in the app comes from a named policy, so reviewing `angular#unsafe-bypass` usage is the same job as reviewing every bypass call. - **Graceful degradation.** Browsers without Trusted Types ignore the directives; the guide notes the app keeps working and is still protected by Angular's sanitizer. ## Reading a violation A Trusted Types violation names the **sink** that rejected a plain string, such as an `innerHTML` assignment or a script `src`, and the stack trace points at the code that wrote it. Three patterns cover most Angular cases: - the stack goes through Angular's binding code and the value came from a bypass method: allow `angular#unsafe-bypass` or, better, stop bypassing; - the stack goes through the lazy-loading path when navigating to a lazy route: allow `angular#bundler`; - the stack goes through your own directive or a third-party widget: a direct DOM write that Angular never sanitized, which needs a code fix. ## Rolling it out - Configure the same header for production serving, for `ng serve` (the guide points to the `headers` option in `angular.json`) and for unit and end-to-end test runs, so violations surface before production. - Start by allowing only `angular`; every violation you see names a feature that needs a policy or a fix. - Prefer **removing** the feature over allowing an `unsafe` policy: replace a bypass with sanitized content, and replace JIT with AOT. - Third-party libraries that write to sinks need their own policies or replacement; Angular's names cover only Angular's code.
- Why does a missing Angular policy not fail at bootstrap?Angular creates each policy lazily and wraps `createPolicy` in a try/catch; on failure it falls back to plain strings so the app still boots. The error only surfaces when a feature relying on that policy writes to a sink, and the browser rejects the plain string.
- Under enforcement, does a sanitized [innerHTML] binding need angular#unsafe-bypass?No. Angular's HTML sanitizer returns its output through the `angular` policy, so ordinary sanitized bindings work with `trusted-types angular` alone. Only values produced by `DomSanitizer` bypass methods go through `angular#unsafe-bypass`.
The trusted-types directive is a guest list at a door that only admits wristbanded values; Angular hands out wristbands from five named booths, and if a booth is not on the list its guests are turned away at the door, not at the booth.
saying these in an interview costs you the question
- Allowing only angular#unsafe-bypass is enough for any Angular app.
- A missing Angular policy stops the app from bootstrapping at all.
- Trusted Types enforcement disables Angular's own HTML sanitizer.
- Browsers without Trusted Types support refuse to run the app.
- Angular's policies also cover third-party libraries that write innerHTML.