cloudfoundry / cloudfoundry/stratos
CSP: raise the policy to Level 3 strict
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 267
- Forks
- 137
- Avg merge
- 5h 14m
- Merged PRs (30d)
- 77
Description
With #5742 merged, the ZAP finding tracked in #5689 no longer reproduces and
the element half of #5705 is shipped. The scanner is quiet, but the policy is
not yet at the strongest level CSP offers. This issue collects what is left, so
the remaining steps are tracked somewhere their titles describe them.
Where the policy stands after #5742
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
style-src-elem 'self' 'nonce-PLACEHOLDER' https://fonts.googleapis.com;
font-src 'self' data: https://fonts.gstatic.com;
img-src 'self' data:;
connect-src 'self';
worker-src 'self' blob:;
frame-ancestors 'self';
base-uri 'self';
form-action 'self'
Style elements are nonce-enforced, which is the CSP Level 3 mechanism for them.
Scripts are still governed by a host allowlist, which is CSP Level 1 thinking,
and several modern directives are absent.
A note on measurement
ZAP will not drive this work. Rule 10055 is satisfied and ZAP has no notion of
"how strict is this policy" beyond the specific patterns it looks for — it will
report a host-based script-src 'self' as perfectly fine. Anything below that
depends on 'strict-dynamic' should be judged with a tool that grades policies,
such as Google's CSP Evaluator, and confirmed in a browser with a violation
listener the way #5742 was. Worth saying up front so nobody chases a green
scanner as evidence of having finished.
The steps, roughly in order of value per unit of risk
1. object-src 'none'. Not declared today, so it inherits default-src 'self', which still permits same-origin plugin content. Every strict-CSP
reference profile sets this to 'none'. One token, no runtime behaviour to
break.
2. Violation reporting. No report-to endpoint exists, so an operator who
turns CSP on and hits a problem discovers it only when a user notices something
unstyled. Even report-only telemetry would have shortened the #5705
investigation considerably. This also makes every later step in this list
safely deployable, which is why it should come early rather than last.
3. script-src 'nonce-…' 'strict-dynamic'. The main event, and the step
that actually moves the policy to Level 3 strict. Under strict-dynamic the
host allowlist is ignored and trust propagates from nonced scripts to the
scripts they load, which is what makes an injected <script src="/…"> useless
to an attacker even when it is same-origin.
The server-side plumbing already exists: cspHeaderWithNonce substitutes every
occurrence of the placeholder, not just the first, so adding the token to a
second directive needs no backend change. What does need work is
injectNonce, which stamps <style> and <app-root> today and would need to
stamp the two build-emitted <script type="module"> tags as well.
The open question is Angular's lazy chunks. They arrive by dynamic import()
from an already-nonced module, which should inherit trust under
'strict-dynamic', but that needs verifying in a browser across a
lazy-route navigation rather than reasoning about — the failure mode is a route
that silently fails to load. The built-UI rig from #5742 is the right
instrument; ng serve cannot test any of this because it never runs
Jetstream's document handler.
4. Trusted Types (require-trusted-types-for 'script'). The strongest
option available and the largest lift. Angular supports it, but Monaco and
xterm are both unknowns, and #5705 is a good reminder of how that tends to go.
Worth scoping only after step 3 lands.
5. style-src-attr. Listed for completeness and explicitly not planned
here. It cannot be fixed by policy — CSP has no nonce or hash for attribute
values computed at runtime, and Monaco's per-line positioning and xterm's
per-cell colours are exactly that. It needs upstream conversion to the CSSOM,
which CSP exempts. Tracked at microsoft/vscode#288813.
Adjacent: the residual scanner warnings
The post-#5742 baseline scan leaves eight warnings, none High or Medium.
They are unrelated to CSP and unchanged by it, but they are the same class of
work and are cheap to fold in:
- Strict-Transport-Security not set (Low, high confidence). Genuine, though
in most deployments TLS terminates at a router in front of Jetstream, so the
right layer needs deciding rather than assuming. - Permissions-Policy not set (Low). Straightforward addition.
- Cross-Origin-Opener/Embedder/Resource-Policy not set (Low). COOP is the
one with real value; COEP has knock-on effects on cross-origin resources and
should not be added casually.
Two more are low-confidence pattern matches on the minified bundle and want a
human look before being treated as real: Dangerous JS Functions (one hit,
lowest confidence) and Timestamp Disclosure (five hits, lowest confidence —
ZAP flags any ten-digit number as a Unix timestamp, which in a minified bundle
is close to meaningless).
The remaining informational entries are cache observations, and one of them is
self-inflicted on purpose: Non-Storable Content on the console document is
a direct consequence of the Cache-Control: no-store the nonce mechanism
requires. It should stay exactly as it is, and is noted here so it does not get
"fixed" by someone reading the scan cold.
Scope
Steps 1 and 2 are small and independent. Step 3 is the substantial one and
should be its own PR with the same before/after browser evidence #5742 used.
Steps 4 and 5 are not proposed for now.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with cspHeaderWithNonce and injectNonce, then review the built-UI rig from #5742 rather than relying on ng serve. Use CSP Evaluator and browser violation evidence to assess the policy, including lazy-route navigation. Done means the scoped strict-CSP steps are verified without breaking the UI; Trusted Types and style-src-attr are explicitly out of scope.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, typescript
- Domain
- backend, frontend, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100