Skip to content

feat(protect): off_origin match type for open-redirect detection - #109

Merged
patchstackdave merged 1 commit into
mainfrom
feat/open-redirect-detection
Aug 12, 2026
Merged

feat(protect): off_origin match type for open-redirect detection#109
patchstackdave merged 1 commit into
mainfrom
feat/open-redirect-detection

Conversation

@patchstackdave

Copy link
Copy Markdown
Contributor

Why

Threading the request into the response phase (#106) unlocked response rules that compare the request to the response. The first and most demoable is open-redirect: a vulnerable endpoint that 302-redirects to an attacker-controlled off-site URL. Previously the skill listed this as "needs an engine change."

What

New off_origin response-phase match type (dispatched like cross_origin, since it needs the whole resolver):

  • Matches (→ action: block) when a 3xx response's Location host differs from the request Host.
  • A relative or same-origin Location never matches; lenient when there's no request Host (can't compare → don't flag). So it can't false-positive without the signal.

Also: reqContextFromFetch now derives the request Host from the URL (a fetch Request doesn't expose a Host header), which origin-comparing response rules need. This is what makes off_origin — and later CORS-reflection — work on the fetch path.

Not a default rule — legitimate off-site redirects are common (OAuth, payments). It's authored and route-scoped:

{ "phase": "response", "category": "open-redirect", "action": "block",
  "when": { "path": "/auth/callback" },
  "rule_v2": [{ "match": { "type": "off_origin" } }] }

Tests

tests/protect/open-redirect.test.ts — 6: off-origin blocked, same-origin/relative allowed, non-3xx ignored, no-request-context lenient, when route scope. 632 pass; typecheck clean.

Follow-up

Update the triage-vpatch-npm skill: move open-redirect from "not yet supported" to a real template. (Separate change — the skill lives in triage-tools + the hub's vendored copy.)

🤖 Generated with Claude Code

Add an `off_origin` response-phase primitive: true (→ block) when a 3xx redirect's Location
header points to a different origin than the request's own Host. Relative / same-origin
Locations never match; lenient when the request Host is unknown. This is the first capability
unlocked by threading the request into the response phase (#106).

Also derive the request Host from the URL in reqContextFromFetch — a fetch Request doesn't
expose a Host header, and origin-comparing response rules (open-redirect, later CORS) need it.

Not a default rule (many apps redirect off-site legitimately); it's authored and route-scoped
via `when`. +6 tests; 632 pass; typecheck clean.

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

coderbuds Bot commented Aug 12, 2026

Copy link
Copy Markdown

Adds focused open-redirect detection with clear origin comparison logic.

🎯 Quality: 100% Elite · 📦 Size: Small

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

See how your team is trending →

@patchstackdave

Copy link
Copy Markdown
Contributor Author

/review

@patchstackdave
patchstackdave merged commit f796704 into main Aug 12, 2026
4 checks passed
@patchstackdave
patchstackdave deleted the feat/open-redirect-detection branch August 12, 2026 11:30
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