Unauthenticated API docs and OAuth error detail leakage #69
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: MEDIUM
The bugs
Two small unauthenticated information leaks.
1. Interactive docs are public.
backend/app/main.py:17constructsFastAPI(title="Circa API", version="0.1.0")with nodocs_url=None/redoc_url=None/openapi_url=Noneand no auth dependency./docs,/redoc, and/openapi.jsonare reachablewithout a session, publishing every route, parameter, and schema. This contradicts
docs/circa-spec.md§2.3 ("all endpoints require authentication except the auth entry/callbackflow") and hands an attacker a complete machine-readable map of the attack surface, including
the ingest endpoint's field names.
2. The OAuth callback reflects raw exception text.
backend/app/api/routes/auth.py:39-42:A broad catch interpolating the exception into a client-visible response on a
pre-authentication endpoint. Authlib exceptions can embed the token endpoint URL, provider
error payloads, and occasionally request parameters — useful for fingerprinting the Authentik
setup before attempting the
aud/PKCE attacks.Fix
docs_url=None if settings.environment != "development" else "/docs", same for redoc andopenapi — or gate them behind an admin dependency.
to the client. Catch specific Authlib exception types rather than bare
Exception.Done when
/docs,/redoc,/openapi.jsonare unreachable outside developmentReferences
backend/app/main.py:17backend/app/api/routes/auth.py:39-42docs/circa-spec.md§2.3Fixed in
791d117. CI green.Docs disabled outside development.
docs_url,redoc_url, andopenapi_urlareNoneunlessis_development. They previously published every route, parameter, and schema to anyone who couldreach the host — including the ingest endpoint's field names — which contradicts the spec's §2.3
"all endpoints require authentication" and removed the guesswork from every other finding.
OAuth errors no longer reflected. The callback caught broadly and interpolated the exception into
a client-visible response, on the one pre-authentication endpoint that talks to an external service.
Authlib exceptions can embed the token endpoint URL, provider error payloads, and request
parameters. It now logs the exception server-side (with
exc_info) and returns a generic"Authentication failed".
Note the broad
except Exceptionis retained deliberately — narrowing it to specific Authlib typesrisks letting an unanticipated exception propagate as a 500 with a traceback, which is the outcome
this is meant to prevent. The fix is not leaking the detail, not catching less.