Skip to content

fix(security): last open-redirect check uses safeRedirectPath - #667

Merged
sh1pt-actions-fleet[bot] merged 1 commit into
masterfrom
fix/open-redirect-same-origin
Oct 28, 2026
Merged

sh1pt-actions-fleet[bot] merged 1 commit into
masterfrom
fix/open-redirect-same-origin

Conversation

@sh1pt-actions-fleet

Copy link
Copy Markdown
Contributor

The auth redirect targets (api/auth/coinpay, callback/oauth returnTo, LoginForm, auth/confirm) were already moved to the same-origin helper in #654 and verified live (returnTo for /%09/evil.com, /%5Cevil.com, //evil.com, https://evil.com all fall back to /dashboard; /ok?x=1 kept).

This PR closes the last ad-hoc startsWith(\"/\") && !startsWith(\"//\") check (NotificationsList data.link) and pins the audit cases in tests.

  • vitest src/lib/safe-redirect.test.ts: 46 passed
  • vitest src/components/notifications: 13 passed

🤖 Generated with Claude Code

…dit open-redirect cases

The last ad-hoc startsWith('/') && !startsWith('//') check (NotificationsList)
was bypassable by /%09/evil and /\evil. Adds explicit tests for
/%09/evil.com, /\evil.com, //evil.com, https://evil.com, /ok?x=1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sh1pt-actions-fleet
sh1pt-actions-fleet Bot merged commit b4d8c2a into master Oct 28, 2026
5 checks passed
@sh1pt-actions-fleet
sh1pt-actions-fleet Bot deleted the fix/open-redirect-same-origin branch October 28, 2026 23:48
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

66 finding(s)

HIGH/CRITICAL: 1 | MEDIUM: 12 | LOW: 53

Severity Rule Location
HIGH js-ssrf-outbound-request scripts/scan-all-skills.ts:38
MEDIUM js-open-redirect src/app/agent-login/AgentLoginForm.tsx:38
MEDIUM js-unescaped-html-sink src/app/blog/[slug]/page.tsx:80
MEDIUM js-open-redirect src/app/checkout/CheckoutClient.tsx:77
MEDIUM js-open-redirect src/app/dashboard/subscription/page.tsx:102
MEDIUM js-open-redirect src/app/dashboard/subscription/page.tsx:114
MEDIUM js-unescaped-html-sink src/app/page.tsx:70
MEDIUM js-unescaped-html-sink src/app/pricing/page.tsx:84
MEDIUM js-open-redirect src/components/funding/FundingClient.tsx:138
MEDIUM js-open-redirect src/components/gigs/BuyNowButton.tsx:120
MEDIUM js-unescaped-html-sink src/components/layout/PitFooter.tsx:25
MEDIUM js-dynamic-code-execution src/lib/skills/metadata-extract.ts:300
MEDIUM js-dynamic-code-execution src/lib/skills/security-scan.ts:48
LOW secret-generic-credential cli/src/commands/auth.test.ts:66
LOW secret-generic-credential cli/src/commands/auth.test.ts:85
LOW secret-generic-credential cli/src/commands/webhooks.test.ts:60
LOW secret-generic-credential cli/src/commands/webhooks.test.ts:72
LOW secret-generic-credential cli/src/commands/webhooks.test.ts:109
LOW secret-generic-credential cli/src/commands/webhooks.test.ts:112
LOW secret-generic-api-key docs/agents/integration-guide.md:893
LOW secret-generic-credential src/app/api/auth/agent-register/route.test.ts:27
LOW secret-generic-credential src/app/api/auth/login/route.test.ts:53
LOW secret-generic-credential src/app/api/auth/login/route.test.ts:68
LOW secret-generic-credential src/app/api/auth/login/route.test.ts:87
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:172
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:196
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:215
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:228
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:267
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:297
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:329
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:346
LOW secret-generic-credential src/app/api/gigs/[id]/buy/route.test.ts:46
LOW secret-generic-credential src/app/api/gigs/[id]/buy/route.test.ts:118
LOW secret-generic-credential src/app/api/gigs/[id]/buy/route.test.ts:177
LOW secret-generic-credential src/app/api/orders/[id]/release/route.test.ts:18
LOW js-dynamic-code-execution src/app/api/skills/[slug]/scan/route.test.ts:212
LOW js-dynamic-code-execution src/app/api/skills/[slug]/scan/route.test.ts:223
LOW js-dynamic-code-execution src/app/api/skills/[slug]/scan/route.test.ts:239
LOW secret-generic-credential src/lib/api.test.ts:126
LOW secret-generic-credential src/lib/api.test.ts:131
LOW secret-generic-credential src/lib/coinpay-oauth.test.ts:20
LOW js-dynamic-code-execution src/lib/skills/composite-scanner.test.ts:106
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:36
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:44
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:66
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:81
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:94
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:103
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:118

…and 16 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

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