fix(security): remove localhost CORS origin, consolidate CORS in proxy#4658
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
️✅ There are no secrets present in this pull request anymore.If these secrets were true positive and are still valid, we highly recommend you to revoke them. 🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request. |
PR SummaryHigh Risk Overview Embedded chat/form API handlers (
Reviewed by Cursor Bugbot for commit 5968f3b. Configure here. |
Greptile SummaryThis PR consolidates all
Confidence Score: 5/5Safe to merge. The change removes a production misconfiguration and replaces it with a well-tested runtime policy table with no regressions. All addCorsHeaders call-sites and dead OPTIONS handlers are cleanly removed. The new resolveApiCorsPolicy covers every previously configured route, the embed path logic correctly guards reserved segments, and getEnv() dynamic lookup correctly reads NEXT_PUBLIC_APP_URL at runtime rather than build time. No files require special attention. Important Files Changed
Reviews (4): Last reviewed commit: "fix(cors): allow PUT in embed CORS polic..." | Re-trigger Greptile |
Move all /api/* CORS handling from next.config.ts to proxy.ts so the runtime can resolve allowed origin per-request instead of baking it at build time (which produced "Access-Control-Allow-Origin: http://localhost:3000" with credentials:true in production). - proxy.ts: per-route CORS policy table covering auth, MCP, form, and workflow execute endpoints; OPTIONS preflight short-circuit; Vary: Origin when origin is not '*'; form routes defer to route handler's addCorsHeaders to avoid double-setting - next.config.ts: drop all /api/* Access-Control-Allow-* headers; keep COEP/COOP/CSP - deployment.ts: addCorsHeaders sets Vary: Origin alongside reflected Allow-Origin - Dockerfile: drop NEXT_PUBLIC_APP_URL build placeholder (Zod has skipValidation:true; build path doesn't read it) - Remove 8 dead OPTIONS handlers and their preflight tests now that the proxy handles preflight uniformly
d8b6cfa to
e168fab
Compare
…ruth Move CORS for /api/chat/* and /api/form/* into the proxy policy table with reflected-origin + credentials:false, and delete the per-route addCorsHeaders helper. Routes no longer set CORS headers — the proxy is the only writer. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… tests Replace the if/else chain in resolveApiCorsPolicy with a CORS_RULES table so each route's policy lives in one place and is trivially scannable. Add proxy.test.ts covering each rule and the wildcard-with-credentials invariant. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@greptile |
|
@cursor review |
The embed policy (reflected origin, credentials:false) was matching workspace-internal session-authed routes — /api/chat, /api/chat/manage/*, /api/chat/validate, and the form equivalents — which need the default credentialed policy. Tighten the matcher to the embed paths only and add tests covering the exclusion. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The regex form `^/api/(chat|form)/(?!manage|validate)[^/]+(/(otp|sso))?$` was opaque on review and would silently exclude any future identifier subroute outside the hard-coded (otp|sso) group from the embed policy. Replace it with an imperative segment check and a named EMBED_RESERVED_SEGMENTS Set, so the policy boundary is visible at the top of the function and adding a reserved subpath is a one-line diff. Add a test asserting that future identifier subroutes also get the embed policy. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@greptile |
|
@cursor review |
Both /api/chat/[identifier]/otp and /api/form/[identifier]/otp export PUT for OTP code verification. The embed policy advertised only GET/POST/OPTIONS, so cross-origin embed clients failed preflight on verify. Add PUT and assert it in the embed policy test. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 5968f3b. Configure here.
#4665) * fix(docker): restore NEXT_PUBLIC_APP_URL build arg with dummy fallback getBaseUrl() in lib/core/utils/urls is evaluated at module load during next build's page-data collection and throws if NEXT_PUBLIC_APP_URL is unset. PR #4658 removed the build arg, breaking the Docker build at the "/_not-found" page-data collection step. Restore the dummy localhost fallback (mirroring DATABASE_URL). The CORS fix from #4658 is preserved: next.config.ts no longer reads NEXT_PUBLIC_APP_URL at build time, and no module-level expression captures getBaseUrl() — every caller invokes it at request time, where getEnv() reads the deployed container env. The dummy localhost value cannot leak into runtime CORS response headers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore(docker): trim verbose comment on build-time env args Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
/api/*CORS handling fromnext.config.tstoproxy.tsso allowed origin is resolved per-request at runtime instead of baked at build time (which producedAccess-Control-Allow-Origin: http://localhost:3000withcredentials: truein production)NEXT_PUBLIC_APP_URLbuild placeholder from Dockerfile (Zod hasskipValidation: true; build path doesn't read it)Type of Change
Testing
Tested manually
Checklist