Skip to content

fix: add timeout and size limit to SAML metadata fetch - #2885

Open
Dextheking1 wants to merge 3 commits into
supabase:masterfrom
Dextheking1:fix/saml-metadata-fetch-limits
Open

Dextheking1 wants to merge 3 commits into
supabase:masterfrom
Dextheking1:fix/saml-metadata-fetch-limits

Conversation

@Dextheking1

Copy link
Copy Markdown

fetchSAMLMetadata used http.DefaultClient and io.ReadAll with no bounds. A metadata_url that serves a huge body, or one that never finishes responding, ties up the fetch until the remote side gives up and reads unbounded memory. This also runs on the ACS path when cached metadata goes stale, so it does not need an admin call to trigger, just a provider whose metadata endpoint misbehaves.

Fix: dedicated client with a 10s timeout (same as OIDC discovery fetches) and a 5 MiB cap on the response body with an explicit error past the cap. Real single-IdP metadata is far below the cap.

Tests: new internal tests in ssoadmin_fetch_test.go cover the happy path, an oversized body, and a server that never responds.

@Dextheking1
Dextheking1 requested a review from a team as a code owner October 23, 2026 05:31
Comment thread internal/api/ssoadmin.go Outdated
Comment on lines +204 to +208
client := &http.Client{
Timeout: samlMetadataFetchTimeout,
}

resp, err := client.Do(req)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use a timeout context, not a new client.

Comment thread internal/api/ssoadmin.go
}

data, err := io.ReadAll(resp.Body)
data, err := io.ReadAll(io.LimitReader(resp.Body, maxSAMLMetadataSize+1))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the data is compressed (usually is) this protects from nothing. There's a better way, reading the Content-Length and rejecting first, then using a LimitReader and rejecting if Content-Length doesn't match (illegal HTTP).

@Dextheking1

Copy link
Copy Markdown
Author

done both. timeout now comes from a context on the request with DefaultClient, no separate client. size check now rejects on Content-Length first, then LimitReader on the decoded body, then rejects if the read length does not match Content-Length. gzip responses skip the length match since the transport decompresses them. added a gzip test, the four fetch tests pass locally.

This branch has not been deployed

No deployments
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.

2 participants