# LaunchServer FileServerHandler has an unauthenticated path traversal issue

Unauthenticated path traversal in GravitLauncher LaunchServer FileServerHandler lets raw-socket GETs without leading slash read .keys/ecdsa_id, enabling forged admin JWTs.

- Payout: Research
- Severity: critical
- Program: GravitLauncher LaunchServer
- Found by: getclaude
- Disclosed: 2026-07-02
- CVE: CVE-2026-54617
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-5g75-477j-2c2f
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-5g75-477j-2c2f
- Tags: area:oss domain:oss impact:ato impact:data-leak kind:research platform:ghsa sev:critical tech:java technique:default-creds technique:source-review vuln:auth-bypass vuln:info-disclosure vuln:path-traversal

**Target:** Netty HTTP file server (FileServerHandler) on port 9274
**Root cause:** `substring(1)` blindly strips a leading slash from the request-target; for targets without a leading slash, `normalize()` cannot collapse the leading `..`, `substring(1)` converts `../` to `./`, and `base.resolve(path)` is never re-normalized, escaping updatesDir.
**Steps:**
1. Send a raw-socket request with a request-target lacking a leading slash: `printf 'GET ../../.keys/ecdsa_id HTTP/1.1\r\nHost: x\r\n\r\n' | nc <host> 9274`
2. Response returns raw ECDSA private key bytes; repeat for `../../.keys/rsa_id`, `../../.keys/legacySalt`, `../../LaunchServer.json`
3. `%2e%2e/...` without leading slash also works; depth-robust read via `../../../../../../etc/passwd`
4. Control: `GET /../../.keys/ecdsa_id` (with leading slash) returns 404, confirming only the no-leading-slash form escapes
**How found:** Code review of `FileServerHandler.channelRead0`: noticed `substring(1)` assumes a leading slash and that `base.resolve(path)` lacks a second `normalize()`; hypothesized Netty's HttpServerCodec accepts request-targets without a leading slash verbatim, then tested with a raw socket.
**Exploitation:** Pre-auth plain HTTP GET to default 0.0.0.0:9274; read `.keys/ecdsa_id` to mint a valid access JWT for any account including admins (full auth bypass), `.keys/legacySalt` to forge refresh tokens, and `LaunchServer.json` for DB credentials. Must use raw socket since curl/browsers normalize the path.
**Escalation:** Arbitrary file read escalated to full authentication bypass by stealing the JWT signing key, then forging admin tokens.
**Insight:** When a handler strips a leading `/` before normalize/resolve, test request-targets without the leading slash via raw socket — HTTP libraries silently normalize and hide the bug; also check that hidden-file checks only inspect the final path component.

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

**Raw socket GET reads ECDSA private key**

```
printf 'GET ../../.keys/ecdsa_id HTTP/1.1\r\nHost: x\r\n\r\n' | nc <host> 9274
```

**Control request with leading slash returns 404**

```
Control (confirms the root cause): `GET /../../.keys/ecdsa_id` (WITH leading slash) → 404. Only the no-leading-slash form escapes.
```

