Skip to content
Hidden Logic Lab

Review Content-Security-Policy and security headers before merge

Cursor or Claude Code applies a SKILL.md on header diffs: script-src relaxations, unsafe-inline, missing frame-ancestors, and report-only policies that never enforce — with merge-blocking findings.

·Coding·30 min·Working

A headers-review SKILL.md beside the app config, a PR comment diffing the effective policy, and no production CSP merged that widens script sources without a named reason.

  1. 1

    Paste the live production header once

    Store it in the skill appendix. Agents compare the PR to that snapshot, not to a tutorial CSP.

  2. 2

    Review a header-only diff

    The comment should say which directives got wider. A summary that only says looks fine is a failed review.

  3. 3

    Keep report-only on a clock

    If report-only is allowed, name the date it must become enforcing. An open-ended report-only policy does not stop XSS.

The prompt to paste

Write SKILL.md for reviewing Content-Security-Policy and companion security headers before merge. Focus on what the browser is allowed to load and frame. This is not a middleware auth review.

Repository context:
[where headers are set: next.config, middleware, netlify.toml, nginx, or a meta tag]
[environments: which policy is report-only vs enforcing]
[script hosts the product already needs: analytics, payments, fonts — names only]
[frame policy: may this app be embedded, and by which parents]

PR context (paste when using):
[PR link, header diff, reason the author gave]

SKILL.md must include:
1. Purpose — a wider script-src or a missing frame-ancestors turns an XSS or clickjack into a silent production bug.
2. When to use — any PR that edits CSP, HSTS, X-Frame-Options, Referrer-Policy, or Permissions-Policy. When not to use — route matcher or session-check changes with no header diff (middleware auth review), or copy edits.
3. Hard rules for findings:
   - Block: production policy adds 'unsafe-eval' or 'unsafe-inline' to script-src without a nonce or hash; script-src * or https: as a blanket host; object-src left as *; frame-ancestors removed or set to * on an authenticated app; enforcing policy replaced by report-only to clear console errors; CSP deleted from the response.
   - Warn: new third-party script host without a ticket naming the vendor; style-src 'unsafe-inline' expanded when a nonce already exists; missing base-uri 'self' or 'none'; missing form-action restriction; HSTS max-age lowered; Referrer-Policy moved to unsafe-url.
   - Note: report-to endpoint naming and header formatting — never block merge on whitespace alone.
4. Review steps the agent must execute:
   - Extract the before and after policy as directives, not as a single blob.
   - Mark each directive that became wider. A new host is wider. Dropping a nonce is wider.
   - Separate report-only from enforcing. A green report-only deploy is not an enforced policy.
   - Check frame-ancestors against the product's embed rules. Do not assume X-Frame-Options still wins when CSP is present.
   - Confirm the header is on document responses and on error pages the browser still renders.
5. PR comment template: directive diff table (directive — before — after — wider?), environment (report-only or enforce), findings, merge recommendation.
6. Safe patterns section: nonce or hash for scripts, explicit host list, frame-ancestors 'none' unless a parent is named, keep report-only only as a short-lived companion to an enforcing policy.
7. Two example prompts: add a payments script host vs turn on unsafe-inline to silence a styled-component warning.
8. Pitfalls: reviewing the meta tag and missing the header the CDN actually sends, copying a docs example with unsafe-inline, treating a staging report-only policy as the production one, ignoring service workers that ship their own policy.
9. Done means: every Block resolved, the effective production policy quoted in the comment, no new script host without an owner.

Rules:
- Do not invent directives that are not in the diff. If the current policy is absent from the paste, write [paste current CSP].
- Do not suggest disabling CSP on production routes.
- Output only SKILL.md markdown.

Browsers ignore X-Frame-Options when frame-ancestors is set. The skill must Block a frame-ancestors * change even if DENY is still present on the older header.

Sample case written by Hidden Logic Lab. Not affiliated with Cursor or Claude Code.

More in Coding

Get new cases in your inbox

Weekly notes on new use cases and agent workflows. No product pitches.

Occasional notes on new cases. No product pitches in the first note.