Skip to content

feat(protect): response header-mutation actions (set / remove / harden-cookie) - #111

Merged
patchstackdave merged 1 commit into
mainfrom
feat/response-header-mutation
Aug 12, 2026
Merged

feat(protect): response header-mutation actions (set / remove / harden-cookie)#111
patchstackdave merged 1 commit into
mainfrom
feat/response-header-mutation

Conversation

@patchstackdave

Copy link
Copy Markdown
Contributor

Why

Response rules could redact a body span or block the whole response — but for header-based issues (CORS misconfig, missing security headers, weak cookies) "block the whole response" is the wrong tool. This adds header mutation so a rule can strip the offending header and still serve the response.

Completes the output-filtering / hardening story before wiring the pieces together: pairs with cors_reflected (#110) — detect the misconfig, then strip Access-Control-Allow-Credentials rather than 500 the endpoint.

What — three actions

  • set-header + set_headers: { name: value } — set/overwrite; ensure: true sets only when absent (won't clobber an existing CSP / X-Frame-Options).
  • remove-header + remove_headers: [names] — strip named headers.
  • harden-cookie — add missing HttpOnly / Secure / SameSite to every Set-Cookie (no duplication; cookie_flags overrides the defaults).
// strip a CORS misconfig instead of blocking the endpoint
{ "phase": "response", "action": "remove-header",
  "remove_headers": ["access-control-allow-credentials"],
  "rule_v2": [{ "match": { "type": "cors_reflected" } }] }

// add security headers to every response on a route (won't clobber existing)
{ "phase": "response", "action": "set-header", "ensure": true,
  "set_headers": { "x-content-type-options": "nosniff", "x-frame-options": "DENY" },
  "when": { "path": "/*" },
  "rule_v2": [{ "parameter": "response.status", "match": { "type": "isset" } }] }

Plumbing

  • Header mutations fold into the existing redact-verdict rebuild path.
  • A null header value now means "delete" — added to both rebuildResponse (fetch) and the node adapter.
  • rebuildResponse now guards null-body statuses (204/205/304/101) so hardening a redirect/no-body response doesn't throw.
  • Block-mode-gated (dry-run observes, doesn't mutate), consistent with redact/block. Not a default — authored + route-scoped.

Tests

tests/protect/response-header-mutation.test.ts — 6: remove (CORS strip, served not blocked), set-header ensure (add + don't-clobber), overwrite, harden-cookie (add + no-duplicate), mutation on a 302 (status/Location preserved), dry-run no-op. 640 pass; typecheck clean.

Follow-up

Add header-mutation templates to the triage-vpatch-npm skill (CORS-strip, security-header ensure, cookie-harden) — separate change (skill lives in triage-tools + the hub's vendored copy).

🤖 Generated with Claude Code

…n-cookie)

Add three response-hardening actions so a matched rule mutates the outgoing response's headers
instead of blocking the whole response — the right mitigation for CORS misconfig, security-header
insertion, and cookie hardening:

- `set-header` + `set_headers: {name: value}` — set/overwrite, or `ensure: true` to add only when
  absent (don't clobber an existing CSP/X-Frame-Options).
- `remove-header` + `remove_headers: [names]` — strip a header (e.g. Access-Control-Allow-Credentials
  on a CORS misconfig, so the response is still served but not cross-origin-readable).
- `harden-cookie` — add missing HttpOnly/Secure/SameSite to Set-Cookie (no duplication;
  `cookie_flags` overridable).

Plumbing: header mutations fold into the existing redact-verdict path; a `null` header value now
signals removal in both rebuildResponse (fetch) and the node path; rebuildResponse guards null-body
statuses (204/205/304/101) so hardening a redirect/no-body response doesn't throw. Block-mode-gated
(dry-run observes only), like redact/block. Not a default — authored + route-scoped.

+6 tests; 640 pass; typecheck clean.

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

coderbuds Bot commented Aug 12, 2026

Copy link
Copy Markdown

Well-structured header-mutation feature with clear, comprehensive tests.

🎯 Quality: 100% Elite · 📦 Size: Medium

📈 This month: Your 49th PR — above team average · Averaging Excellent

See how your team is trending →

@patchstackdave

Copy link
Copy Markdown
Contributor Author

/review

@patchstackdave
patchstackdave merged commit fa39700 into main Aug 12, 2026
4 checks passed
@patchstackdave
patchstackdave deleted the feat/response-header-mutation branch August 12, 2026 11:52
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.

2 participants