Summary
pgAdmin 4's default CONTENT_SECURITY_POLICY allowed 'unsafe-inline' and 'unsafe-eval' in script-src, which leaves the policy unable to stop an injected inline script — the main protection a CSP is meant to provide.
Inline scripts now run under a per-request nonce instead:
- A per-request nonce is generated with
secrets.token_urlsafe and cached on flask.g, so the same value is emitted in the templates and in the CSP response header.
- A
{nonce} placeholder in CONTENT_SECURITY_POLICY is substituted at runtime.
- Inline
<script> and <style> tags carry the nonce.
- The new default is
script-src 'self' 'nonce-{nonce}', with neither 'unsafe-inline' nor 'unsafe-eval'.
Two deliberate limits:
style-src keeps 'unsafe-inline'. MUI and React inject runtime styles and inline style="" attributes that cannot carry a nonce.
- Development bundles are built with webpack's
eval devtool, which a strict nonce policy blocks. get_content_security_policy() appends 'unsafe-eval' to script-src automatically when config.DEBUG is set and the policy uses a nonce, so developers no longer have to add it by hand in config_local.py. Production is unaffected, and a custom non-nonce policy passes through untouched.
Fix
Fixed in pgAdmin 4 9.18 by commit fb0ca5c4c.
Unit tests cover nonce generation, caching and per-request freshness, {nonce} substitution, pass-through of custom/None/empty policies, header emission, and the development-mode behaviour.
Not a vulnerability report
This is a hardening change to pgAdmin's own default policy rather than a fix for a reported flaw, so no CVE has been requested.
Summary
pgAdmin 4's default
CONTENT_SECURITY_POLICYallowed'unsafe-inline'and'unsafe-eval'inscript-src, which leaves the policy unable to stop an injected inline script — the main protection a CSP is meant to provide.Inline scripts now run under a per-request nonce instead:
secrets.token_urlsafeand cached onflask.g, so the same value is emitted in the templates and in the CSP response header.{nonce}placeholder inCONTENT_SECURITY_POLICYis substituted at runtime.<script>and<style>tags carry the nonce.script-src 'self' 'nonce-{nonce}', with neither'unsafe-inline'nor'unsafe-eval'.Two deliberate limits:
style-srckeeps'unsafe-inline'. MUI and React inject runtime styles and inlinestyle=""attributes that cannot carry a nonce.evaldevtool, which a strict nonce policy blocks.get_content_security_policy()appends'unsafe-eval'toscript-srcautomatically whenconfig.DEBUGis set and the policy uses a nonce, so developers no longer have to add it by hand inconfig_local.py. Production is unaffected, and a custom non-nonce policy passes through untouched.Fix
Fixed in pgAdmin 4 9.18 by commit
fb0ca5c4c.Unit tests cover nonce generation, caching and per-request freshness,
{nonce}substitution, pass-through of custom/None/empty policies, header emission, and the development-mode behaviour.Not a vulnerability report
This is a hardening change to pgAdmin's own default policy rather than a fix for a reported flaw, so no CVE has been requested.