CORS defaults to "*" while allow_credentials is True #20

Closed
opened 2026-08-20 03:06:27 -04:00 by logan · 0 comments
Owner

app/main.py:79-85 mounts CORSMiddleware with allow_origins=settings.cors_origins and allow_credentials=True, and config.py:102 defaults cors_origins to ["*"].

Starlette treats that combination specially: rather than refusing it, it reflects the caller's Origin back in Access-Control-Allow-Origin and still sends Access-Control-Allow-Credentials: true. So the effective policy is "any origin, with credentials" — the opposite of what a wildcard normally means.

Honest severity: lower than it looks. c2-core authenticates with bearer tokens (Firebase ID token, service key, node API key), and a browser does not attach those automatically cross-origin, so an attacker page cannot ride an existing session the way it could with cookie auth. The drb_session cookie exists but c2-core never reads it — it only drives the Next middleware's UX redirect. This is a misconfiguration waiting for the day something does start trusting a cookie or an origin, not a live account-takeover path today.

Whether production is actually running the wildcard is unverified: CORS_ORIGINS may be set in the server's .env, which is gitignored and not readable from here. Note that drb-c2-core/.env.example is known-stale, so its absence there proves nothing.

Fix: make the bad combination unrepresentable rather than relying on every deployment remembering to override it. If cors_origins contains "*", either force allow_credentials=False or refuse to start, and log at ERROR naming the variable to set. The default in config.py should be the real frontend origin, with the wildcard opt-in for local development.

From the 2026-08-05/06 security audit, listed there as the open MEDIUM item.

`app/main.py:79-85` mounts `CORSMiddleware` with `allow_origins=settings.cors_origins` and `allow_credentials=True`, and `config.py:102` defaults `cors_origins` to `["*"]`. Starlette treats that combination specially: rather than refusing it, it reflects the caller's `Origin` back in `Access-Control-Allow-Origin` and still sends `Access-Control-Allow-Credentials: true`. So the effective policy is "any origin, with credentials" — the opposite of what a wildcard normally means. **Honest severity:** lower than it looks. c2-core authenticates with bearer tokens (Firebase ID token, service key, node API key), and a browser does not attach those automatically cross-origin, so an attacker page cannot ride an existing session the way it could with cookie auth. The `drb_session` cookie exists but c2-core never reads it — it only drives the Next middleware's UX redirect. This is a misconfiguration waiting for the day something does start trusting a cookie or an origin, not a live account-takeover path today. Whether production is actually running the wildcard is unverified: `CORS_ORIGINS` may be set in the server's `.env`, which is gitignored and not readable from here. Note that `drb-c2-core/.env.example` is known-stale, so its absence there proves nothing. **Fix:** make the bad combination unrepresentable rather than relying on every deployment remembering to override it. If `cors_origins` contains `"*"`, either force `allow_credentials=False` or refuse to start, and log at ERROR naming the variable to set. The default in `config.py` should be the real frontend origin, with the wildcard opt-in for local development. From the 2026-08-05/06 security audit, listed there as the open MEDIUM item.
logan closed this issue 2026-08-23 01:26:34 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: logan/server-26#20