Every CVESearch/Get API key

CVE-2026-59179

OpenHop: Path Traversal in Flow ID File Operations

8.3 HighFix available

OpenHop is a tool for creating interactive data-flow diagrams. Prior to 0.3.7, @openhop/server passes unauthenticated flow route parameters from GET /api/flows/:id and DELETE /api/flows/:id in packages/server/src/routes.ts to FlowStore.filePath() in packages/server/src/store.ts without an identifier allow-list. The router applies decodeURIComponent to the id, and path.join() then normalizes traversal outside the configured flow directory after appending the .yaml extension. An attacker can read accessible YAML files as YAML-parsed JSON or permanently delete accessible .yaml files outside that directory, exposing configuration or secrets and disrupting dependent services. In packages/server/src/index.ts, CORS origin: true permits any browser origin, enabling a malicious webpage to target a loopback-bound instance. Docker deployments default to HOST=0.0.0.0 and permit direct unauthenticated network access. This issue is fixed in repository release 0.3.7.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
Required

What an attacker can affect

Confidentiality
Low
Integrity
High
Availability
High

Exploit likelihood

0.39%Unchanged since Oct 29, 2026
90%50%10%1%

What each source reports

CVE List Score used8.3

OpenHop: Path Traversal in Flow ID File Operations

OpenHop is a tool for creating interactive data-flow diagrams. Prior to 0.3.7, @openhop/server passes unauthenticated flow route parameters from GET /api/flows/:id and DELETE /api/flows/:id in packages/server/src/routes.ts to FlowStore.filePath() in packages/server/src/store.ts without an identifier allow-list. The router applies decodeURIComponent to the id, and path.join() then normalizes traversal outside the configured flow directory after appending the .yaml extension. An attacker can read accessible YAML files as YAML-parsed JSON or permanently delete accessible .yaml files outside that directory, exposing configuration or secrets and disrupting dependent services. In packages/server/src/index.ts, CORS origin: true permits any browser origin, enabling a malicious webpage to target a loopback-bound instance. Docker deployments default to HOST=0.0.0.0 and permit direct unauthenticated network access. This issue is fixed in repository release 0.3.7.

Record
CVE-2026-59179
CVSS 3.1
8.3 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
Weakness
CWE-22
Updated
2026-11-02
EUVDEUVD-2026-1120808.3

OpenHop is a tool for creating interactive data-flow diagrams. Prior to 0.3.7, @openhop/server passes unauthenticated flow route parameters from GET /api/flows/:id and DELETE /api/flows/:id in packages/server/src/routes.ts to FlowStore.filePath() in packages/server/src/store.ts without an identifier allow-list. The router applies decodeURIComponent to the id, and path.join() then normalizes traversal outside the configured flow directory after appending the .yaml extension. An attacker can read accessible YAML files as YAML-parsed JSON or permanently delete accessible .yaml files outside that directory, exposing configuration or secrets and disrupting dependent services. In packages/server/src/index.ts, CORS origin: true permits any browser origin, enabling a malicious webpage to target a loopback-bound instance. Docker deployments default to HOST=0.0.0.0 and permit direct unauthenticated network access. This issue is fixed in repository release 0.3.7.

Record
EUVD-2026-112080
CVSS 3.1
8.3 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-g72f-jw3w-mgh78.3

@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:

// 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):

# 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:

curl -i --path-as-is 'http://127.0.0.1:8799/api/flows/..%2Fvictim'

Expected response:

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 flow store…
Record
GHSA-g72f-jw3w-mgh7
CVSS 3.1
8.3 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
Weakness
CWE-22
Updated
2026-11-02
NVD8.3

OpenHop is a tool for creating interactive data-flow diagrams. Prior to 0.3.7, @openhop/server passes unauthenticated flow route parameters from GET /api/flows/:id and DELETE /api/flows/:id in packages/server/src/routes.ts to FlowStore.filePath() in packages/server/src/store.ts without an identifier allow-list. The router applies decodeURIComponent to the id, and path.join() then normalizes traversal outside the configured flow directory after appending the .yaml extension. An attacker can read accessible YAML files as YAML-parsed JSON or permanently delete accessible .yaml files outside that directory, exposing configuration or secrets and disrupting dependent services. In packages/server/src/index.ts, CORS origin: true permits any browser origin, enabling a malicious webpage to target a loopback-bound instance. Docker deployments default to HOST=0.0.0.0 and permit direct unauthenticated network access. This issue is fixed in repository release 0.3.7.

Record
CVE-2026-59179
CVSS 3.1
8.3 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
Weakness
CWE-22
Updated
2026-11-05
OSV8.3

OpenHop: Path Traversal in Flow ID File Operations

OpenHop is a tool for creating interactive data-flow diagrams. Prior to 0.3.7, @openhop/server passes unauthenticated flow route parameters from GET /api/flows/:id and DELETE /api/flows/:id in packages/server/src/routes.ts to FlowStore.filePath() in packages/server/src/store.ts without an identifier allow-list. The router applies decodeURIComponent to the id, and path.join() then normalizes traversal outside the configured flow directory after appending the .yaml extension. An attacker can read accessible YAML files as YAML-parsed JSON or permanently delete accessible .yaml files outside that directory, exposing configuration or secrets and disrupting dependent services. In packages/server/src/index.ts, CORS origin: true permits any browser origin, enabling a malicious webpage to target a loopback-bound instance. Docker deployments default to HOST=0.0.0.0 and permit direct unauthenticated network access. This issue is fixed in repository release 0.3.7.

Record
CVE-2026-59179
CVSS 3.1
8.3 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
Weakness
CWE-22
Updated
2026-11-05
OSVGHSA-g72f-jw3w-mgh78.3

@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:

// 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):

# 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:

curl -i --path-as-is 'http://127.0.0.1:8799/api/flows/..%2Fvictim'

Expected response:

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 flow store…
Record
GHSA-g72f-jw3w-mgh7
CVSS 3.1
8.3 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
Weakness
CWE-22
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
@openhop/server
npm
through 0.3.5
0.3.6
@openhop/server
npm
before 0.3.6
0.3.6

History

History
RecordedChangedSources
factsNVD
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-59179 is a high vulnerability (CVSS 8.3) in Naorsabag Openhop, published September 9, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.39%, the 33rd percentile. Fixed in @openhop/server 0.3.6.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open