Fix: anchor api auth idor - #289
Open
Bran18 wants to merge 2 commits into
Open
Conversation
|
@Bran18 is attempting to deploy a commit to the Oppia Software Labs Team on Vercel. A member of the Team first needs to authorize it. |
|
@Bran18 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #280
Closes an IDOR across the anchor and automation API surface by adding wallet-signed authentication, server-side session cookies, and per-resource ownership checks before any upstream anchor call.
Previously, all nine /api/anchor/** routes were unauthenticated BFF proxies: Zod validated input shape, but customerId, email, transactionId, and publicKey were caller-supplied with no proof of ownership. That exposed regulated PII (CLABE numbers, KYC records) and let anonymous traffic use our anchor credentials.
This PR implements the full auth model from the security plan:
Authentication — Stellar signed-challenge flow (POST /api/auth/challenge → sign → POST /api/auth/verify) with single-use, TTL-bounded nonces and an HttpOnly neko_session cookie (secure, sameSite=strict).
Authorization — Upstash-backed (provider, customerId) → publicKey bindings (written at customer creation) and transaction bindings for on/off-ramp GETs. Unknown bindings fail closed with 403.
Route hardening — All 9 anchor routes and 6 automation routes call requireSession before upstream work. Off-ramp validates fiatAccountId ownership; assets?wallet= is restricted to the session wallet; email-based customer lookup is removed.
Defence in depth — Middleware returns 401 for /api/anchor/* and /api/automation/* without a session cookie. Per-IP and per-session rate limits return 429 before anchor quota is consumed. Shared handleAnchorError removes raw exception/upstream text from responses.
Client — rampApi.ts sends credentials, retries on 401 via challenge/verify, and surfaces an “authenticate your wallet” state in the ramp UI.
KYC uploads — Size cap, MIME allowlist, and document count limits on multipart doc_* fields.
Admin UI gating (neko-stellar-address cookie for /dashboard/admin) is unchanged and remains a separate, UX-only concern.
Breaking changes:
Existing customerId values in localStorage without a server binding will receive 403 until the user re-onboards via authenticated POST /customers.
Client payloads no longer accept identity fields (publicKey, stellarAddress); the server derives them from the session.
GET /customers?email= is removed; lookup is customerId only, with ownership enforced.
New environment variables that mati or the team will need to add:
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
AUTH_SESSION_SECRET=
AUTH_ENFORCEMENT=true