AEV-2026-0043
OpenMAIC validates a BYOK provider base URL once, then follows an unrevalidated redirect to it (GHSA-725p-44hx-v52c)
OpenMAIC's validateUrlForSSRF correctly rejects a bring your own key provider base URL that resolves directly to a private or metadata address. The server's own subsequent fetch, read directly by this entry at the v1.0.0 tag, uses default HTTP redirect following with no per hop check, so a public address that answers with a redirect to a private target is reached anyway. Fixed in 1.0.1 by revalidating every redirect hop and stripping provider credential headers on a cross origin hop.
Affected
- Organisation
- THU-MAIC
- Product
- OpenMAIC
- Component
- validateUrlForSSRF in lib/server/ssrf-guard.ts, called once from lib/server/resolve-model.ts, ahead of an unguarded globalThis.fetch in lib/ai/providers.ts
- Versions
- Through version 1.0.0; fixed in 1.0.1
- Configurations
- A deployment exposing the bring your own key provider base URL as a caller supplied value; The caller controls or can induce a response from the initially supplied public origin, which then issues its own HTTP redirect toward a private, loopback, link local or cloud metadata address
Execution authority facts
Fields the evidence does not establish are shown as unknown rather than guessed.
- Intended task
- OpenMAIC resolves and validates a caller supplied bring your own key provider base URL before making a completion request to it
- Agent
- OpenMAIC's own server process, through resolve-model.ts and the provider fetch in providers.ts
- Delegating actor
- The operator who deploys OpenMAIC and the caller who supplies the bring your own key base URL
- Action
- Validated the caller supplied origin hostname once, then issued a fetch with default redirect following that, on receiving a 3xx response from that origin, connected automatically to whatever address the response's Location header named, with no second validation call
- Target resource
- Whatever private, loopback, link local or cloud metadata destination the initially validated public origin's own redirect names
- Environment
- Wherever the operator deploys the OpenMAIC server process
- Credentials used
- The caller's own bring your own key provider credential, carried in the request's authorization, api-key, x-api-key or x-goog-api-key header through the same request configuration the redirect follows
- Privileges available
- The OpenMAIC server process's own network reachability from its deployment location
- Authority presented
- A bring your own key provider base URL that validateUrlForSSRF's own DNS classification of the origin hostname did not reject
- Authority required
- Authorization for the specific destination the redirect actually pointed the next request at
- Applicable policy
- validateUrlForSSRF, which runs once against the caller supplied origin and is never called again against a redirect's own target
- Approval mechanism
- none
- Required approver
- unknown
- Independent approval
- no
- Action binding
- The validation decision bound to the origin hostname the caller supplied; the destination actually contacted was not independently checked once a redirect substituted a different one
- Sequence context
- The redirect follows automatically inside the same outbound fetch that the initial validation was meant to gate, with no application level checkpoint between the two requests
Impact
- Consequence
- OpenMAIC's own server process reaching a private, loopback, link local or cloud metadata destination it would have rejected had the caller supplied it directly, demonstrated by the advisory's own positive control against a redirecting public origin
- Reach
- organisational
- Reversibility
- unknown
- Detectability
- unknown
- Propagation
- Not established as observed against a real internal service or cloud metadata endpoint beyond the advisory's own proof of concept target; this entry does not claim a specific credential was exfiltrated to an attacker controlled endpoint through this mechanism
- Recovery
- Fixed in 1.0.1, which this entry read directly: fetchWithRedirectValidation sets redirect to manual, resolves each Location header against the current URL, calls validateUrlForSSRF again before following it, fails closed on a rejected destination, bounds the chain to five hops, rejects a missing or malformed Location header, refuses to replay a streaming body across a hop, and strips the authorization, api-key, x-api-key and x-goog-api-key headers once a hop crosses origin.
Evidence
Primary sources
- SSRF protection bypass via unvalidated HTTP redirect on BYOK base URL (THU-MAIC/OpenMAIC (GitHub Security Advisories))
Supporting sources
- Release v1.0.1 (THU-MAIC/OpenMAIC (GitHub Releases))
- fetch-with-redirect-validation.ts at v1.0.1 (THU-MAIC/OpenMAIC (GitHub, source))
- ssrf-guard.ts at v1.0.0 (validateUrlForSSRF) (THU-MAIC/OpenMAIC (GitHub, source))
- resolve-model.ts at v1.0.0 (BYOK base URL validation call) (THU-MAIC/OpenMAIC (GitHub, source))
- providers.ts at v1.0.0 (unguarded provider fetch) (THU-MAIC/OpenMAIC (GitHub, source))
- Unauthenticated outbound SSRF to cloud metadata service via fail-open middleware and environment-gated validation bypass (THU-MAIC/OpenMAIC (GitHub Security Advisories))
- Reproduction status
- Vendor disclosed and vendor patched, with the advisory's own proof of concept controls, a direct private target rejected and a redirecting public target followed, stated in the advisory's own words. This session did not itself deploy OpenMAIC or run the redirect against a self hosted listener; it read the affected source at the v1.0.0 tag and the fixed source at the v1.0.1 tag directly through this session's page fetch and summarization tool rather than raw byte for byte retrieval.
- Evidence state
- Confirmed
Known unknowns
- Whether this has been exploited against a real OpenMAIC deployment. Neither advisory states active exploitation, and no independent report of one was found.
- Whether a specific caller's own bring your own key credential was ever demonstrated reaching an attacker controlled endpoint through this mechanism, as distinct from the advisory's own demonstrated destination substitution.
- Whether any hostname used in the advisory's own proof of concept resolved differently between the validation call and the actual connection, which would implicate DNS rebinding specifically rather than the HTTP redirect mechanism this entry documents.
- Whether a formally assigned CVE identifier for GHSA-725p-44hx-v52c exists; none appears in the advisory as read by this session.
Limitations
- This session's direct fetch of the CVE Program's own record at cve.org was blocked by this session's network egress policy for both GHSA-725p-44hx-v52c and GHSA-9m7h-vh2h-rc3w.
- Every source in this entry was retrieved through this session's automated page fetch and summarization tool rather than read as raw markup or raw file bytes; this entry's own provenance notes state where that tool's account of an exact line number differs from the primary advisory's own citation.
Claim provenance
- verified
GitHub's own security advisory, fetched directly, states the affected range (through 1.0.0), the fixed version (1.0.1), Moderate severity at CVSS 4.0 base 6.9, no assigned CVE, the reporter, the four affected source locations, and the negative and positive proof of concept controls this entry's summary and impact fields restate.
The Destination Was Authorized. The Redirected Destination Was Not. - verified
This session read the affected source directly at the v1.0.0 tag, confirming validateUrlForSSRF performs a single DNS classification of a hostname and is called exactly once against a caller supplied bring your own key base URL, inside a conditional gated on process.env.NODE_ENV being production, a separate fact this entry connects to GHSA-9m7h-vh2h-rc3w rather than to this occurrence's own mechanism.
The Destination Was Authorized. The Redirected Destination Was Not. - verified
This session read the affected source directly at the v1.0.0 tag, confirming a globalThis.fetch call in the bring your own key completion path carries the caller's own request configuration forward with no redirect option specified, defaulting Node's fetch to following a redirect automatically with no intervening application level check.
The Destination Was Authorized. The Redirected Destination Was Not. - verified
This session read the fixed source directly at the v1.0.1 tag and the release's own notes, confirming fetchWithRedirectValidation sets redirect to manual, revalidates every Location target against validateUrlForSSRF before following it, fails closed, bounds the chain to five hops, and strips the authorization, api-key, x-api-key and x-goog-api-key headers once a hop's resolved origin differs from the current one.
The Destination Was Authorized. The Redirected Destination Was Not. - verified
This session read this separate, Critical rated advisory directly and confirmed its own distinct mechanism, an unauthenticated middleware fail open plus an environment gated validateUrlForSSRF call skipped entirely outside production, is not conflated with this entry's own occurrence, in which the same validation call runs and correctly rejects a direct private target before the redirect specific gap this entry documents.
The Destination Was Authorized. The Redirected Destination Was Not.
