skip to content

You are deploying a strict nonce-based CSP for an Angular banking dashboard; what does Angular itself require in the policy, and which app features would force you to loosen it?

level: seniorimportance: should knowfreq 32%

answer

  1. the guide's minimal policy
  2. styles need the nonce
  3. script nonce for inlined critical CSS
  4. JIT, JSONP, bypasses
  5. fix the feature, not the policy

basics

~20 s

Angular's minimal policy is default-src 'self' plus a per-response nonce in style-src and script-src, handed to Angular via ngCspNonce or CSP_NONCE. JIT compilation, JSONP, bypassed values under Trusted Types and missing nonce plumbing are what push teams to loosen it.

solid answer

~40 s

Start from the guide's minimal policy: `default-src 'self'; style-src 'self' 'nonce-…'; script-src 'self' 'nonce-…'`. The style nonce exists because Angular inserts component styles as `<style>` elements at runtime, so it must receive the per-response value through `ngCspNonce` or `CSP_NONCE`. The script nonce is only needed when the build inlines critical CSS, and then the nonce must come from `ngCspNonce` or `autoCsp`, not the token. An AOT build needs no `'unsafe-eval'`. What forces loosening is usually a feature. A JIT bootstrap needs `'unsafe-eval'`. If you cannot generate nonces, you are left with `'unsafe-inline'` for styles. JSONP calls need the external host in `script-src`. Under Trusted Types, bypass calls need `angular#unsafe-bypass`. For a banking dashboard the right move is to remove each feature rather than widen the policy.

go deeper

for a junior

Recall the guide's minimal policy: default-src 'self', and a nonce in style-src and script-src.

for a middle

Explain why each directive is there, especially that style-src needs the nonce because Angular inserts component styles at runtime.

for a senior

Audit the app for features that force loosening, such as JIT, JSONP, bypasses and missing nonce plumbing, and replace them instead of widening the header.

for a principal

Own the risk posture: which relaxations are acceptable for a money-moving app, who signs off, and how the policy stays strict as features are added.

## The target: what Angular needs and nothing more A strict CSP for a high-value app such as a banking dashboard aims to let only the app's own code run. Angular's security guide gives the **minimal policy** a new Angular app needs: ```txt default-src 'self'; style-src 'self' 'nonce-randomNonceGoesHere'; script-src 'self' 'nonce-randomNonceGoesHere'; ``` Reading it directive by directive: | Directive | Why Angular needs it | | :--- | :--- | | `default-src 'self'` | the bundle, assets and API calls come from the app's own origin | | `style-src 'self' 'nonce-…'` | global stylesheets from the origin, plus the `<style>` elements Angular inserts for component styles | | `script-src 'self' 'nonce-…'` | bundled scripts from the origin; the nonce is only required when critical CSS is inlined | Notice what is absent: no `'unsafe-inline'` and no `'unsafe-eval'`. An AOT build never evaluates strings as code, so it does not need the latter. ## Step 1: give Angular the nonce The nonce must be random and **unique per response**; the guide stresses it must not be predictable. Angular then needs the value so it can stamp it on the styles it inserts: 1. **`ngCspNonce` on the root element** when the server renders `index.html` per response. 2. **`CSP_NONCE` injection token** when the value is available at runtime and `index.html` should be cacheable. 3. **`autoCsp`** in the workspace configuration, the CLI-driven route. If the build **inlines critical CSS**, the guide says to use the attribute or `autoCsp`, because the token cannot reach styles written into the HTML file. With server-side rendering and hydration's event replay, the same token also supplies the nonce for the inline replay script Angular adds to the page. ## Step 2: find the features that fight the policy Each of these is a common reason teams end up weakening the header: - **JIT compilation** (`platformBrowserDynamic`, the runtime compiler) needs `'unsafe-eval'`. Fix: build with AOT; the JIT bootstrap package is deprecated since Angular 20. - **No nonce plumbing**: without a nonce, component styles are blocked and the only fallback the guide offers is `'unsafe-inline'` in `style-src`. Fix: pick one of the three channels above. - **JSONP** through `HttpClient` injects a `<script>` from another origin. Angular stamps the nonce on it, but the host is still external code executing in your page. Fix: use CORS-enabled JSON endpoints instead; `withJsonpSupport()` is deprecated since Angular 22.1 for exactly this XSS risk. - **Bypassed values** under Trusted Types need `angular#unsafe-bypass`. Fix: sanitize instead of bypassing wherever possible. - **Lazy routes** under Trusted Types need `angular#bundler`. This one is expected and safe to allow. ## Step 3: verify before enforcing Use the same header in development and tests as in production, so a missing nonce shows up as unstyled components in `ng serve` rather than in front of customers. Typical first-run symptoms and their Angular causes: - components render without styling: the nonce is not reaching Angular; - a blank page with an eval violation: something is still compiled JIT; - only certain widgets fail under Trusted Types: they rely on a bypass or write to the DOM directly. How the nonce travels from the edge to the HTML, `strict-dynamic`, and report-only rollouts are general CSP deployment topics; the Angular-specific part is the list above. ## A rollout checklist for the dashboard 1. Build with AOT and confirm the bootstrap uses `bootstrapApplication`. 2. Choose the nonce channel from how `index.html` is served, and handle critical-CSS inlining if the build uses it. 3. Remove JSONP calls and review every `bypassSecurityTrust*` call. 4. Apply the header in development, tests and staging before production. 5. Add Trusted Types enforcement with `angular` and `angular#bundler` once the CSP itself is clean. ## The judgment call For a dashboard that moves money, every loosening token is a standing risk, so the default answer is to **change the feature, not the policy**. The one relaxation Angular's guide itself offers, `'unsafe-inline'` for styles when nonces are impossible, is weaker but far less dangerous than anything in `script-src`. `'unsafe-eval'` or a broad script host list should be treated as a blocker, not a trade-off.

  • Does an AOT-built Angular app ever need 'unsafe-eval' in script-src?
    Not for Angular itself: templates are compiled at build time and nothing is evaluated from strings at runtime. If a violation mentions eval, look for a JIT bootstrap, the runtime compiler or a third-party library that evaluates strings.
  • The dashboard uses server-side rendering; what else needs the nonce?
    When hydration's event replay is in use, Angular's server rendering adds a small inline script that starts replaying events captured before the app booted, and it puts the `CSP_NONCE` value on that script. So the per-request nonce must be provided to the server-side application as well, not only in the browser.

saying these in an interview costs you the question

  • Angular's minimal CSP needs 'unsafe-eval' for template bindings.
  • Angular generates and injects the nonce itself, so the server does nothing.
  • One nonce value can be reused across responses if it is long enough.
  • 'unsafe-inline' in script-src is the guide's recommended fallback.
  • JSONP is fine under a strict CSP because Angular adds the nonce.