fix(security): stop granting every origin credentialed access to the API (#5)

`AURUM_CORS_ORIGINS` defaults to `*`, and the middleware was configured with
`allow_credentials=True`. Starlette does not answer that combination with a
literal `*` — it echoes back whatever `Origin` the caller sent and adds
`Access-Control-Allow-Credentials: true`, so any page open in the same
browser can call the instance, with the user's Basic Auth attached, and read
the response:

    GET /api/accounts   Origin: https://evil.example
    -> Access-Control-Allow-Origin: https://evil.example
       Access-Control-Allow-Credentials: true

That undercuts the README's advice that leaving Basic Auth off is fine while
the instance is only reachable from localhost: reachable-from-localhost
includes every website the user visits.

Nothing in the shipped setup is cross-origin. Compose serves the UI and the
API from the same nginx, and the Vite dev server proxies `/api`
(frontend/vite.config.ts), so neither deployment nor development needs CORS
at all. The default is therefore empty — no cross-origin access — and the
middleware is only installed when origins are configured deliberately.

An explicit `*` is still honoured for a genuinely public read-only setup, but
never together with credentials, which is what the spec intends `*` to mean
anyway.
This commit is contained in:
technosexual
2026-08-30 18:11:09 +03:00
committed by GitHub
parent 3013466c05
commit b045d378f0
5 changed files with 65 additions and 12 deletions

View File

@@ -8,8 +8,13 @@ AURUM_POSTGRES_HOST=db
AURUM_POSTGRES_PORT=5432
# --- Backend ---
# Comma-separated list of allowed origins, or * for any (fine for local self-hosting).
AURUM_CORS_ORIGINS=*
# Comma-separated list of browser origins allowed to call the API. Leave it
# empty unless you serve the frontend from a different origin than the API:
# docker compose serves both from the same nginx, and the Vite dev server
# proxies /api, so neither needs this. "*" is honoured but then credentials
# are never granted, because "*" plus credentials lets any site you visit
# read this instance.
AURUM_CORS_ORIGINS=
AURUM_DEFAULT_CURRENCY=USD
# --- Crypto tab (live prices via CoinGecko) ---