ZeroHour

CVE-2026-59179

1

Unauthenticated Path Traversal in @openhop/server npm package

CVSS 3.1
8.3 high
EPSS
Published
()
Modified
AI analysis

The @openhop/server npm package passes unsanitized Fastify route parameters directly into path.join() when constructing filesystem paths for flow YAML files, allowing path traversal (CWE-22). An unauthenticated attacker sends GET or DELETE requests to /api/flows/:id with URL-encoded traversal sequences (e.g., ..%2F), which are decoded by the router and normalized by path.join() to escape the configured flow directory, yielding arbitrary .yaml file reads and arbitrary .yaml file deletions anywhere the process can reach. Because the server sets CORS to allow any origin, a victim's browser can be tricked into attacking a loopback-bound instance, and Docker deployments that bind HOST=0.0.0.0 by default are directly reachable over the network, which drives the High 8.3 CVSS score (network vector, no privileges, user interaction for the CORS-based vector, high impact on integrity and availability via file deletion). Anyone running the affected server is at risk, with Docker deployments and locally-running instances exposed through distinct paths. There is currently no known public proof-of-concept and the flaw is not in the CISA KEV catalog.

What to do: Upgrade to a patched @openhop/server release as soon as one is published, since no fixed version is identified in the available data. Until patched, restrict network exposure (bind to loopback rather than 0.0.0.0 in Docker, use a firewall or reverse-proxy allowlist) and consider validating the :id route parameter against a strict pattern that rejects path separators and '..' sequences. Check audit logs for unauthenticated GET/DELETE requests to /api/flows/ containing encoded slashes or dot-segments, and verify that no unexpected .yaml files outside the flow directory have been read or deleted.

Affected
OpenHop (@openhop scope, npm) @openhop/server
Estimated exposure
No basis for an estimate.

Order-of-magnitude estimate by the model from install counts, market share and public scan data it knows; verify before quoting.

Description

@openhop/server: Path Traversal in Flow ID File Operations ## Path Traversal in Flow ID File Operations ### Summary `@openhop/server` passes unsanitized HTTP route parameters directly to `path.join()` when constructing filesystem paths for flow YAML files. An unauthenticated attacker who can reach the server can read arbitrary `.yaml` files accessible to the OpenHop process outside the configured flow directory, and can delete arbitrary `.yaml` files at any path reachable by the process. Because CORS is set to `origin: true` (allow all origins), a victim's browser can be used to exploit the vulnerability against a loopback-bound instance. Docker deployments bind `HOST=0.0.0.0` by default, enabling direct remote exploitation. CVSS Base Score: **8.3 (High)**. ### Details `FlowStore.filePath()` in `packages/server/src/store.ts:52–53` constructs a filesystem path by concatenating the caller-supplied `id` directly into `path.join`: ```ts // packages/server/src/store.ts:52-53 private filePath(id: string): string { return join(this.dir, `${id}.yaml`) } ``` This result is consumed by two sinks: - **Read** (`packages/server/src/store.ts:78`): `readFile(this.filePath(id), 'utf-8')` - **Delete** (`packages/server/src/store.ts:105`): `unlink(this.filePath(id))` The `id` value originates from unauthenticated Fastify HTTP route parameters: - `GET /api/flows/:id` (`packages/server/src/routes.ts:306`) → `store.get(id)` at line 333–335 - `DELETE /api/flows/:id` (`packages/server/src/routes.ts:509`) → `store.delete(id)` at line 539–541 The route parameter schema at `packages/server/src/routes.ts:315` and `519` declares only `type: 'string'` with no pattern constraint or allowlist. Fastify's underlying router (`find-my-way`) applies `decodeURIComponent` to route parameters, so the URL segment `..%2Fvictim` is decoded to `../victim` before it reaches application code. Node.js `path.join('/data/flows', '../victim.yaml')` then normalizes to `/data/victim.yaml`, escaping the configured data directory. Additionally, `packages/server/src/index.ts:37` registers CORS with `origin: true`, permitting any browser origin to make cross-origin requests to the server. This makes the vulnerability exploitable via a malicious webpage against users running OpenHop locally. **Full data-flow (read path):** 1. HTTP `GET /api/flows/..%2Fvictim` received (`routes.ts:306`) 2. `find-my-way` decodes `..%2Fvictim` → `req.params.id = '../victim'` (`routes.ts:333`) 3. `store.get('../victim')` → `filePath('../victim')` → `join('/data/flows', '../victim.yaml')` → `/data/victim.yaml` (`store.ts:52–53`) 4. `readFile('/data/victim.yaml', 'utf-8')` returns file contents (`store.ts:78`) 5. Server responds HTTP 200 with YAML-parsed JSON body **Full data-flow (delete path):** 1. HTTP `DELETE /api/flows/..%2Fdelete-me` received (`routes.ts:509`) 2. `find-my-way` decodes `..%2Fdelete-me` → `req.params.id = '../delete-me'` (`routes.ts:539`) 3. `store.delete('../delete-me')` → `filePath('../delete-me')` → `join('/data/flows', '../delete-me.yaml')` → `/data/delete-me.yaml` (`store.ts:52–53`) 4. `unlink('/data/delete-me.yaml')` removes the file (`store.ts:105`) 5. Server responds HTTP 204 ### PoC **Environment setup (Docker):** ```bash # Build from repository root docker build -f vuln-001/Dockerfile -t openhop-vuln-001 . # Run with HOST=0.0.0.0 (default in the Dockerfile ENV) docker run -d --name openhop-vuln-001 -p 8799:8799 openhop-vuln-001 ``` The container creates `/data/flows/` as the configured flow store (`OPENHOP_DATA_DIR=/data/flows`) and places `/data/victim.yaml` and `/data/delete-me.yaml` outside that directory as traversal targets. **Attack 1 — Read file outside flow store:** ```bash curl -i --path-as-is 'http://127.0.0.1:8799/api/flows/..%2Fvictim' ``` Expected response: ```http HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 {"id":"victim","meta":{"title":"SECRET_OUTSIDE_FILE","description":"This file lives outside the configured fl

Ecosystems
npm
Weakness
CWE-22
Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
GHSA
GHSA-g72f-jw3w-mgh7 (high)

In the news

No ingested article mentions this CVE yet.