source-cooperative / source-cooperative/data.source.coop
Code comments claim the data-connection fetch authorizes the caller; it does not
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 24
- Forks
- 6
- Avg merge
- 1h 32m
- Merged PRs (30d)
- 1
Description
Summary
Two code comments assert that the subject-scoped data-connection fetch authorizes the caller for that connection. It does not — the endpoint authorizes every caller, including anonymous ones. The actual gate is the product fetch.
No known vulnerability follows from this (see below), but the comments describe a security guarantee the system does not provide, and they are load-bearing for anyone reasoning about the federation ordering.
Evidence
GET /api/v1/data-connections/{id} gates on Actions.GetDataConnection, whose implementation is:
// source.coop:src/lib/api/authz.ts
function getDataConnection(
principal: UserSession | null,
_dataConnection: DataConnection
): boolean {
if (principal?.account?.disabled) {
return false;
}
return true;
}
For an anonymous caller principal is null, so principal?.account?.disabled is undefined → falsy → returns true. It has returned true unconditionally since it was introduced.
This is deliberate on the API side — source.coop:src/lib/api/sanitize-data-connection.ts says secret-less authentication config "is returned to any caller (the proxy reads it impersonating the end user)".
The inaccurate comments
src/source_api/cache.rs(get_or_fetch_data_connection): "lets the subject-scoped Source API authorize this exact connection: a caller not entitled to it gets 404/403"src/source_api/registry.rs(resolve_product, step 3 and the confused-deputy note): "the subject-scoped API authorizes this exact resource" / "the subject-scoped Source API fetches above … only return the product/connection this caller is authorized for"
Why the security conclusion still holds
The product fetch is genuinely gated (Actions.GetRepository), and a connection is only ever reached by following a mirror reference from an already-authorized product. So the deny-before-federate ordering is intact; it just rests entirely on the product gate, not on both fetches.
Suggested action
- Correct the two comments so the guarantee is attributed to the product fetch alone.
- Decide whether
getDataConnectionshould gate. Returning connection metadata to any caller who can guess an id is a deliberate choice, but it is worth an explicit decision rather than an implicit one — connection ids are not secrets and the response includes provider, bucket, region, prefix, and the auth type.
Notes
Found while auditing the ADRs in #115 against the implementation. The ADR text making the same claim is being corrected separately; this issue covers the code comments and the API-side question.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read src/source_api/cache.rs and src/source_api/registry.rs alongside src/lib/api/authz.ts and src/lib/api/sanitize-data-connection.ts to verify which fetch performs authorization. Update the two comments to attribute the guarantee to the product fetch, and record the explicit decision about whether getDataConnection should gate callers; done means the comments no longer claim a guarantee the endpoint does not provide.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, typescript
- Domain
- backend-api-design, security
- Issue type
- Documentation
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100