NewApp Monitoring is liveSign up free
AgentbeamBeta
AI agent vulnerability · Other MCP servers and tools

CVE-2026-55156: Token Optimizer MCP: Unauthenticated Path Traversal in Dashboard Session Log API Endpoints

mediumCVSS 3.1 5.3GHSA-76pc-mqxp-3rq5

The dashboard server in `@ooples/token-optimizer-mcp` lets anyone who can reach it read `.jsonl` files outside its log directory. `/api/session-summary` and `/api/session-events` have no authentication and put the `sessionId` query parameter into a file path. Versions before 5.1.0 are affected; the report used 5.0.1. Upgrade to 5.1.0.

Published Aug 14, 2026 · Analysis Oct 25, 2026

What an attacker can do

Both handlers in src/server/web-server.ts build the path with path.join(hooksDataPath, session-log-${sessionId}.jsonl) and then call fs.readFileSync. Node normalises .. segments in the join, so a sessionId such as abc/../../../../traversal-target escapes hooksDataPath. No middleware checks credentials on /api/*. The reporter's single unauthenticated GET to /api/session-events on port 3100 returned HTTP 200 with the content of a .jsonl file outside the hooks directory.

The forced .jsonl suffix narrows what can be read. Even so, the intended targets are rich: the session logs hold tool invocations, hook outputs and token-usage data from AI agent sessions. They can contain file paths, commands and pasted secrets. Any other .jsonl file the process can read is in reach too, such as chat or event exports.

The response sends Access-Control-Allow-Origin: *. So a web page could also make a browser send these requests to a dashboard on localhost or an internal address, though the advisory does not claim that. The risk is highest when the dashboard listens on a non-loopback interface. The attack is confidentiality-only.

Who is affected

npm package @ooples/token-optimizer-mcp, versions < 5.1.0. Only setups that start the dashboard web server are exposed. Check the version:

npm ls -g @ooples/token-optimizer-mcp

Then check which interface and port the dashboard listens on; the report used port 3100.

@ooples/token-optimizer-mcp

Ecosystem
npm
Affected
< 5.1.0
Fixed in
5.1.0
Check
npm ls @ooples/token-optimizer-mcp

How to fix it

Upgrade to 5.1.0, the patched version:

npm install -g @ooples/[email protected]

The fix is in commit b4ee96dac799cbfba0a9f9c17844ce9d613cbcc7. The advisory's remediation lists three steps: allow only sessionId values that match /^[a-zA-Z0-9_-]{1,64}$/, or apply path.basename, and add authentication to all /api/* routes. The sources do not say which of these 5.1.0 uses. Until you upgrade, do not run the dashboard, or keep it bound to loopback and behind a firewall.

How to tell if you were hit

Search the dashboard's access logs, or a reverse proxy in front of it, for requests to /api/session-summary and /api/session-events where sessionId contains .., %2F or %2e. A normal value is a plain identifier. Look for clients you do not recognise on the dashboard port, which was 3100 in the report. If you find a hit, assume that session logs were read and review them for secrets. Beam keeps its own record of agent shell commands and file access, which can help you work out what the logs contained.

Original advisory

From the GitHub Advisory Database (CC BY 4.0).

Unauthenticated Path Traversal in Dashboard Session Log API Endpoints

| Field            | Value |
| Repository       | ooples/token-optimizer-mcp |
| Affected version | 5.0.1 (commit 8137147) |
| Vulnerability    | CWE-22 — Improper Limitation of a Pathname to a Restricted Directory |
| Severity         | Medium |
| CVSS 3.1         | 5.3 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N) |

Summary

The dashboard HTTP server in token-optimizer-mcp exposes /api/session-summary and /api/session-events with no authentication middleware — any network-accessible client can reach them without credentials. Both handlers concatenate the caller-supplied sessionId query parameter directly into a filesystem path via path.join, and Node.js normalizes .. segments at resolution time, allowing an unauthenticated attacker to read any .jsonl file reachable from the server's filesystem. Successful reproduction confirmed exfiltration of a .jsonl file located outside the intended hooksDataPath directory with a single unauthenticated HTTP GET request.

Affected Code

src/server/web-server.ts:73–88 — /api/session-summary: unsanitized sessionId interpolated into path.join then passed to fs.readFileSync

    const hooksDataPath = getHooksDataPath();
    const jsonlFilePath = path.join(
      hooksDataPath,
      `session-log-${sessionId}.jsonl`
    );

    if (!fs.existsSync(jsonlFilePath)) {
      return res.status(404).json({
        success: false,
        error: `JSONL log not found for session ${sessionId}`,
        sessionId,
      });
    }

    // Parse JSONL file
    const jsonlContent = fs.readFileSync(jsonlFilePath, 'utf-8');

src/server/web-server.ts:297–311 — /api/session-events: identical unsanitized path.join + fs.readFileSync pattern

    const hooksDataPath = getHooksDataPath();
    const jsonlFilePath = path.join(
      hooksDataPath,
      `session-log-${sessionId}.jsonl`
    );

    if (!fs.existsSync(jsonlFilePath)) {
      return res.status(404).json({
        success: false,
        error: `JSONL log not found for session ${sessionId}`,
      });
    }

    // Parse JSONL file
    const jsonlContent = fs.readFileSync(jsonlFilePath, 'utf-8');

req.query.sessionId flows unsanitized into path.join(hooksDataPath, \session-log-${sessionId}.jsonl\), which Node.js resolves by normalizing .. traversal sequences before the fs.readFileSync call.

Proof of Concept

Step 1 — Send traversal payload to /api/session-events with no credentials: server returns HTTP 200 with contents of a .jsonl file outside hooksDataPath — proves unauthenticated out-of-bounds file read.

curl -s "http://127.0.0.1:3100/api/session-events?sessionId=abc%2F..%2F..%2F..%2F..%2Ftraversal-target"
GET /api/session-events?sessionId=abc%2F..%2F..%2F..%2F..%2Ftraversal-target HTTP/1.1
Host: 127.0.0.1:3100
User-Agent: python-requests/2.x
Accept: */*
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 186

{"success":true,"sessionId":"abc/../../../../traversal-target","total":1,"offset":0,"limit":100,"events":[{"type":"PATH_TRAVERSAL_EVIDENCE","secret":"sensitive-data-outside-hooks-dir"}]}

Impact

An unauthenticated remote attacker can read the contents of any .jsonl file accessible to the process running the dashboard server. In a typical deployment this includes all session log files (which contain tool invocations, hook outputs, and token usage data) as well as any other .jsonl file reachable via .. traversal from hooksDataPath. The constraint that the resolved path must end in .jsonl limits the attack surface to that file extension, but session logs can contain sensitive operational data. The same path traversal is present in both /api/session-summary and /api/session-events, and neither endpoint requires authentication.

Remediation

  1. Validate `sessionId` format before use: reject any value that does not match a strict allowlist such as /^[a-zA-Z0-9_-]{1,64}$/. This prevents / and . characters from entering the path construction entirely.
   const SESSION_ID_RE = /^[a-zA-Z0-9_-]{1,64}$/;
   if (!SESSION_ID_RE.test(sessionId)) {
     return res.status(400).json({ success: false, error: 'Invalid sessionId' });
   }
  1. Alternatively, apply `path.basename` to strip all directory components: path.basename(sessionId) reduces any traversal sequence to a bare filename before path.join.
  1. Add authentication middleware to all /api/* routes so that even if a bypass is found the endpoints are not reachable without a valid session token.

Credited to 232-323.

Questions

Do I need credentials to exploit this?

No. The two /api endpoints have no authentication, and the reporter's request used none.

What files can be read?

Only files ending in .jsonl, because the code appends that suffix. That includes session logs with tool invocations and hook outputs.

Is the MCP server itself exposed?

The flaw is in the dashboard HTTP server, not the stdio tools. If you do not run the dashboard, this path is not reachable.

Is it fixed in 5.1.0?

Yes. The advisory lists 5.1.0 as patched, and everything below it as vulnerable.

References

How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology

More Other MCP servers and tools vulnerabilities

All Other MCP servers and tools entries