Skip to content

security: harden CORS origin validation on faucet and index-supply#694

Open
MoneyBund wants to merge 2 commits into
tempoxyz:mainfrom
MoneyBund:harden-api-cors-origin-checks
Open

security: harden CORS origin validation on faucet and index-supply#694
MoneyBund wants to merge 2 commits into
tempoxyz:mainfrom
MoneyBund:harden-api-cors-origin-checks

Conversation

@MoneyBund

Copy link
Copy Markdown

Harden CORS origin validation on the faucet and Index Supply endpoints

Severity: Security — origin allowlist bypass

Both public API routes reflect the caller's Origin back into
Access-Control-Allow-Origin after a check that can be trivially satisfied by
an attacker-controlled domain. That defeats the whole point of the allowlist:
any web page can drive authenticated, state-changing POSTs to these
endpoints from a victim's browser.

Two bypasses

1. startsWith prefix match (Index Supply).

allowedOrigins.some((allowed) => origin.startsWith(allowed))

https://tempo.xyz.attacker.com starts with https://tempo.xyz, so it passes
and gets reflected.

2. includes('vercel.app') substring match (both routes).

if (origin?.includes('vercel.app')) allowedOrigins.push(origin)

Preview deployments legitimately live on *.vercel.app, but a substring test
also green-lights https://vercel.app.attacker.com and
https://evil-vercel.app.co.

The fix

Replaced the loose checks with an exact allowlist plus a real host match for
preview URLs, extracted into a small isAllowedOrigin(origin) helper in each
file:

  • exact equality against the known origins (this is what faucet.ts already
    did for its base list — the substring branch was the hole);
  • new URL(origin) parse, then protocol === 'https:' && hostname.endsWith('.vercel.app')
    so only genuine Vercel subdomains match, and a malformed Origin header
    falls through to "denied".

Each endpoint keeps its own base allowlist unchanged
(mainnet.docs.tempo.xyz for Index Supply, docs.tempo.xyz for the faucet)
and the localhost dev entry.

Verification

  • pnpm check:types — clean.
  • Manual reasoning against the bypass strings above: all now rejected;
    https://tempo.xyz, https://<base>, https://foo.vercel.app, and
    http://localhost:5173 (dev only) still allowed.

@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

@MoneyBund is attempting to deploy a commit to the Tempo Team on Vercel.

A member of the Team first needs to authorize it.

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