OpenMAIC's SSRF guard ran only when NODE_ENV was production, and a fail open middleware left every route unauthenticated whenever ACCESS_CODE was unset (GHSA-9m7h-vh2h-rc3w)
OpenMAIC's validateUrlForSSRF is written correctly and reused as a shared helper, but at five call sites, two of them confirmed by this entry's own direct read, every call was wrapped in a check on process.env.NODE_ENV === 'production'. In development, staging, preview or an unset environment, the identical caller supplied provider base URL reached the outbound fetch with no destination check at all, composing with a separately fail open middleware that authenticated nothing when ACCESS_CODE was unset. Fixed in 1.0.1, released the same day as the advisory, which also adds a repository scanning test against a gated call site reappearing; the fail open middleware itself is unchanged.
Affected
- Organisation
- THU-MAIC
- Product
- OpenMAIC, environment-gated validateUrlForSSRF and fail open ACCESS_CODE middleware
- Component
- validateUrlForSSRF call sites named by the advisory (middleware.ts; app/api/generate/image, generate/video, extract-document and parse-pdf routes; lib/server/resolve-model.ts), plus middleware.ts's separate ACCESS_CODE check
- Versions
- Through version 1.0.0, confirmed by this entry's own direct read of two named call sites; fixed in 1.0.1
- Configurations
- Any deployment whose NODE_ENV is not the literal string production at the moment a provider generation, extraction or model resolution request arrives, including an unset NODE_ENV, which is Next.js's own default outside an explicit build or start invocation; Most severe composed with a deployment that never sets ACCESS_CODE, under which middleware.ts's own fail open branch authenticates no API request at all
Execution authority facts
Fields the evidence does not establish are shown as unknown rather than guessed.
- Intended task
- A caller invokes a generation, extraction or model resolution endpoint naming a provider base URL the server should fetch from
- Agent
- OpenMAIC's own server process, through the affected route handlers and the shared resolve-model.ts helper
- Delegating actor
- The operator who deploys OpenMAIC and controls both the ACCESS_CODE and NODE_ENV values the running process reads
- Action
- Issued a server side outbound fetch to a caller named provider base URL with no destination check applied, because the call site's own conditional found NODE_ENV was not the literal string production
- Target resource
- Whatever loopback, link local, private network or cloud metadata destination the caller names as the provider base URL
- Environment
- Wherever the operator deploys the OpenMAIC server process, in any state other than a NODE_ENV of exactly production
- Credentials used
- None required when ACCESS_CODE is unset, confirmed directly against middleware.ts's fail open branch; a valid HMAC verified openmaic_access cookie otherwise
- Privileges available
- The OpenMAIC server process's own network reachability from its deployment location
- Authority presented
- A well formed request naming a provider base URL, under the least restrictive configuration presented with no credential at all
- Authority required
- Authorization for the specific destination the caller directed the server's outbound fetch to
- Applicable policy
- validateUrlForSSRF, confirmed by this entry's own direct read to be written correctly and already wired to five call sites; not reached on any path where NODE_ENV was not exactly production
- Approval mechanism
- none
- Required approver
- unknown
- Independent approval
- no
- Action binding
- The request's authority bound to naming a provider base URL; the destination itself was checked only when a second, independent condition on the server's own deployment classification happened to be true
- Sequence context
- The environment check and the destination check are evaluated together at the same call site, immediately before the outbound fetch; there is no later point in the request where the destination is independently checked
Impact
- Consequence
- The OpenMAIC server process's own outbound fetch directed at a caller named destination with no destination check, demonstrated by the advisory's own attack scenario naming a cloud metadata service path; this entry did not itself operate a live deployment or reproduce credential exfiltration
- Reach
- organisational
- Reversibility
- unknown
- Detectability
- unknown
- Propagation
- Not established as observed against a real cloud metadata service or internal network by this entry's own verification; the advisory states the mechanism, not a confirmed downstream compromise
- Recovery
- Fixed in 1.0.1, released the same day as the advisory. This entry confirmed directly, at the two call sites it independently read, that the NODE_ENV conditional is removed and the destination check now runs unconditionally, and read tests/server/url-guard-unconditional-invariant.test.ts directly, confirming it scans the repository for a validateUrlForSSRF call gated on NODE_ENV and fails the build if one is found. This entry also confirmed directly that 1.0.1's middleware.ts carries the identical fail open branch for an unset ACCESS_CODE, unchanged from 1.0.0; nothing in the release notes or the source this entry could read states that behavior changed.
Evidence
Primary sources
- Unauthenticated outbound SSRF to cloud metadata service via fail-open middleware and environment-gated validation bypass (THU-MAIC/OpenMAIC (GitHub Security Advisories))
- Release v1.0.1 (THU-MAIC/OpenMAIC (GitHub Releases))
Supporting sources
- app/api/generate/image/route.ts at the v1.0.0 tag (NODE_ENV gated SSRF call) (THU-MAIC/OpenMAIC (GitHub, source))
- app/api/generate/image/route.ts at the v1.0.1 tag (guard now unconditional) (THU-MAIC/OpenMAIC (GitHub, source))
- lib/server/resolve-model.ts at the v1.0.0 tag (NODE_ENV gated SSRF call, shared helper) (THU-MAIC/OpenMAIC (GitHub, source))
- lib/server/resolve-model.ts at the v1.0.1 tag (guard now unconditional) (THU-MAIC/OpenMAIC (GitHub, source))
- middleware.ts at the v1.0.0 tag (fail open when ACCESS_CODE is unset) (THU-MAIC/OpenMAIC (GitHub, source))
- middleware.ts at the v1.0.1 tag (fail open branch unchanged) (THU-MAIC/OpenMAIC (GitHub, source))
- lib/server/ssrf-guard.ts at the v1.0.1 tag (ALLOW_LOCAL_NETWORKS) (THU-MAIC/OpenMAIC (GitHub, source))
- tests/server/url-guard-unconditional-invariant.test.ts at the v1.0.1 tag (regression scan) (THU-MAIC/OpenMAIC (GitHub, source))
- CVE-2026-86259 (independent aggregator cross reference; no CVE Program direct read) (Independent CVE tracking aggregators)
- Reproduction status
- Vendor disclosed and vendor fixed the same day. This entry read the affected source directly at both the v1.0.0 and v1.0.1 tags for two of the advisory's five named call sites and for the middleware, confirming the mechanism and the fix; it did not itself deploy OpenMAIC or reproduce an outbound connection to a real cloud metadata service.
- Evidence state
- Confirmed
Known unknowns
- Whether this has been exploited against a real OpenMAIC deployment.
- What share of OpenMAIC deployments run with ACCESS_CODE unset or with a NODE_ENV other than production.
- Whether the three call sites this entry did not itself read, the video, document and PDF routes, match the advisory's own table exactly line for line.
- Whether any cloud provider's credentials have actually been exfiltrated through this mechanism, as distinct from the advisory's own stated attack scenario.
- Whether the CVE Program's own record for CVE-2026-86259 matches the metadata this entry read from GitHub's advisory and independent aggregators, since cve.org was blocked to direct fetch in this session.
Limitations
- This session's direct fetch of the CVE Program's own record at cve.org, and of nvd.nist.gov and osv.dev, was blocked by this session's network egress policy on every attempt; the CVE-2026-86259 identifier is corroborated through independent aggregators rather than read directly from the CVE Program's own record, and GitHub's own advisory page states no known CVE.
- Three of the five call sites the advisory names, the video, document and PDF routes, are carried on the advisory's own table rather than on this entry's own direct read of each file.
- The advisory's own page and the release notes were retrieved through this session's automated page fetch and summarization tool rather than read as raw markup, though the affected source itself was independently confirmed by this entry's own direct read at both tags.
Claim provenance
- verified
GitHub's own Security Advisory, read directly twice, states CVSS 4.0 base 9.3 Critical, CWE-306, CWE-668 and CWE-918, against OpenMAIC through 1.0.0, fixed in 1.0.1, and names five affected call sites and the x-base-url attack scenario. The advisory's own metadata sidebar states no known CVE on both reads.
The Guard Existed. The Deployment Mode Decided Whether It Counted. - verified
This entry read both call sites directly at the v1.0.0 tag, confirming the identical conditional pattern gating validateUrlForSSRF on process.env.NODE_ENV === 'production' at each.
The Guard Existed. The Deployment Mode Decided Whether It Counted. - verified
This entry read both call sites directly at the v1.0.1 tag, confirming the NODE_ENV clause is removed and validateUrlForSSRF now runs unconditionally at each.
The Guard Existed. The Deployment Mode Decided Whether It Counted. - verified
This entry read middleware.ts directly at both tags, confirming the identical fail open branch, if (!accessCode) { return NextResponse.next(); }, unchanged between them.
The Guard Existed. The Deployment Mode Decided Whether It Counted. - verified
This entry read the fixed guard directly, confirming an explicit ALLOW_LOCAL_NETWORKS override that must be set to true or 1 for a caller supplied loopback or private address to be permitted outside production, rather than that access being an implicit default of a non production build.
The Guard Existed. The Deployment Mode Decided Whether It Counted. - verified
This entry read the regression test directly, confirming it scans the repository's own source for a validateUrlForSSRF call sitting inside a conditional referencing NODE_ENV and fails if one is found.
The Guard Existed. The Deployment Mode Decided Whether It Counted. - verified
The v1.0.1 release notes, read directly, state the outbound URL guard ran only in production builds and now runs everywhere with a repository scanning test against regression, and require ALLOW_LOCAL_NETWORKS=true for local model server access outside production; the same notes state no change to ACCESS_CODE or middleware authentication.
The Guard Existed. The Deployment Mode Decided Whether It Counted. - independent-reporting
Independent CVE tracking aggregators, cross referenced through search rather than each read directly, list CVE-2026-86259 against a mechanism matching this entry's own: OpenMAIC before 1.0.1, SSRF validation skipped outside production, cloud instance metadata as the named impact. This entry treats the identifier as corroborated rather than confirmed by a CVE Program direct read, which this session's network egress policy blocked.
The Guard Existed. The Deployment Mode Decided Whether It Counted.
