Skip to content

Feat: Use per-request nonce in CSP to remove 'unsafe-inline' / 'unsafe-eval'#10153

Open
hiteshjambhale wants to merge 2 commits into
pgadmin-org:masterfrom
hiteshjambhale:feat/csp-nonce
Open

Feat: Use per-request nonce in CSP to remove 'unsafe-inline' / 'unsafe-eval'#10153
hiteshjambhale wants to merge 2 commits into
pgadmin-org:masterfrom
hiteshjambhale:feat/csp-nonce

Conversation

@hiteshjambhale

@hiteshjambhale hiteshjambhale commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Addresses #7599 — removing 'unsafe-inline' and 'unsafe-eval' from the Content-Security-Policy.

This introduces a per-request CSP nonce so inline scripts run only when they carry the nonce, instead of relying on a blanket 'unsafe-inline'. 'unsafe-eval' is dropped from the default policy as well.

What changed

  • security_headers.py — generate a per-request nonce (secrets.token_urlsafe), cached on flask.g so the same value is emitted both in the rendered templates and in the Content-Security-Policy response header. A {nonce} placeholder in CONTENT_SECURITY_POLICY is substituted at runtime.
  • __init__.py — expose csp_nonce to templates.
  • Templates (base.html + tool templates) — tag inline <script>/<style> with nonce="{{ csp_nonce }}", and set window.__webpack_nonce__ so webpack's dynamically injected assets carry the nonce too.
  • config.py — new default policy:
    default-src 'self' ws: http: data: blob:;
    script-src 'self' 'nonce-{nonce}';
    style-src 'self' 'unsafe-inline';
    

Notes / scope

  • 'unsafe-eval' is not needed by production bundles (verified). Development bundles use webpack's eval devtool and do need it, so devs add it in config_local.py (documented in config.py).
  • style-src keeps 'unsafe-inline' by necessity: MUI/React inject runtime <style> elements and, more importantly, inline style="" attributes that cannot be covered by a nonce or hash. This matches standard practice for MUI/React apps — the meaningful XSS surface (scripts) is what gets locked down.
  • Backward compatible: if {nonce} is absent from a custom policy, behaviour is unchanged.

Testing

Verified against a production build with the strict policy: app loads, all tools (Query Tool, PSQL, ERD, Schema Diff, Debugger) work, and the JSON editor (ajv / jsonpath-plus) runs cleanly with no 'unsafe-eval' — confirming it can be dropped.

Summary by CodeRabbit

  • Security Enhancements
    • Strengthened Content Security Policy to default to same-origin and improved script protection by removing broad inline/eval allowances.
    • Introduced per-request CSP nonces and applied them across inline scripts and styles throughout the main app and key tools (including debug, ERD, SQL editor, and query pages).
    • Ensured the generated Content-Security-Policy header is set consistently using the new nonce-based configuration.

…al' (pgadmin-org#7599)

Harden the default Content-Security-Policy so inline scripts run only via a
per-request nonce instead of a blanket 'unsafe-inline', and drop 'unsafe-eval'.

- Generate a per-request nonce (secrets.token_urlsafe) cached on flask.g so the
  exact same value is emitted in templates and the CSP response header.
- Substitute a {nonce} placeholder in CONTENT_SECURITY_POLICY at runtime.
- Tag inline <script>/<style> tags, and set window.__webpack_nonce__ so webpack's
  dynamically injected assets carry the nonce too.
- New default: script-src 'self' 'nonce-{nonce}' (no 'unsafe-inline'/'unsafe-eval').
- style-src keeps 'unsafe-inline': MUI/React inject un-nonced runtime styles and
  inline style="" attributes that cannot be nonced.
- 'unsafe-eval' is not needed by production bundles; the dev ('eval' devtool)
  bundles add it via config_local.py (documented in config.py).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The CSP now restricts scripts to same-origin or nonce-authorized execution. A request-scoped nonce is generated, added to response headers, exposed to templates, and applied to inline and bundled scripts and styles.

Changes

Content Security Policy nonce support

Layer / File(s) Summary
Runtime CSP generation
web/config.py, web/pgadmin/utils/security_headers.py
The configured CSP uses {nonce}, while SecurityHeaders generates a request-scoped nonce, resolves the policy, and sets the response header.
Template nonce context and base assets
web/pgadmin/__init__.py, web/pgadmin/templates/base.html
The nonce is added to template context and applied to base inline scripts, styles, vendor bundles, webpack setup, and initialization scripts.
Tool template nonce coverage
web/pgadmin/templates/security/render_page.html, web/pgadmin/tools/*/templates/*
Inline style blocks in security, debugger, ERD, PSQL, schema diff, and SQL editor templates now use the request nonce.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant FlaskRequest
  participant SecurityHeaders
  participant TemplateRenderer
  Browser->>FlaskRequest: request page
  FlaskRequest->>SecurityHeaders: generate request nonce
  SecurityHeaders-->>FlaskRequest: cache nonce in flask.g
  FlaskRequest->>TemplateRenderer: provide csp_nonce
  TemplateRenderer-->>Browser: render nonce-tagged scripts and styles
  SecurityHeaders-->>Browser: send resolved CSP header
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding per-request CSP nonces to replace unsafe inline/eval allowances.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@hiteshjambhale hiteshjambhale changed the title Use per-request nonce in CSP to remove 'unsafe-inline' / 'unsafe-eval' Feat: Use per-request nonce in CSP to remove 'unsafe-inline' / 'unsafe-eval' Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant