Checked the First Field, Missed the Payload: Three New Network-AI CVEs and the Guardrail That Keeps Getting Bypassed
NVD published three CVEs against Jovancoding Network-AI within one minute of each other on 12 October 2026 (17:17:28Z–17:17:29Z), all sourced to disclosure@vulncheck.com, all fixed in 5.15.2. Network-AI is a TypeScript multi-agent orchestrator with guardrails and adapters for 32 AI frameworks — a small project (78 stars, 13 forks, MIT, created February 2026) that this site has covered before, in May, for an MCP cross-origin flaw. The October batch is more interesting than the May one, because its headline record is the second bypass of the same security control in two months — and we read the code on both sides of both fixes.
- CVE-2026-109331 (CVSS 4.0 7.5, 3.1 7.4, CWE-436 Interpretation Conflict, versions 5.14.0 through before 5.15.2). The
ClaudeHookBridgePreToolUse hook matches operator deny patterns against only the first present candidate field of a tool call. A prompt-injected agent can place the dangerous payload inWritecontent or an MCP script parameter beside a benignfile_pathorcommand, evadingdenyPatternsto write web shells or execute scripts. - CVE-2026-109330 (4.0 5.3, 3.1 4.3, CWE-1385, 5.0.0 through before 5.15.2).
DashboardServer.handleUpgradeperforms no Origin or token validation, so a cross-site WebSocket hijack lets a remote attacker lure a victim running the dashboard to a malicious page and read live agent topology: agent IDs, roles, task descriptions, token budgets. - CVE-2026-109332 (4.0 2.3, 3.1 3.1, CWE-346, npm
network-aibefore 5.15.2).McpSseServer._handleRequestreflects localhost Origins intoAccess-Control-Allow-Originregardless of bind interface, so when the server binds a non-loopback address, an attacker page with a localhost Origin can read unauthenticated endpoints like/healthcross-origin.
The same twelve lines, bypassed twice
The August record is what makes the October record a story. On 13 August 2026, also via VulnCheck, CVE-2026-73614 (4.0 8.7, 3.1 8.8, CWE-436, before 5.15.1) found that the same bridge truncated the target string to 500 characters before evaluating deny patterns, while Claude Code executes the full untruncated command — so dangerous content past byte 500 in a Bash command field bypassed the operator’s hard-deny list and executed. That was fixed in 5.15.1. Seven weeks later, the October record shows the untruncated remainder was still only the first field. Two CVEs, two CVSS high scores, one helper function.
We read lib/claude-hooks.ts at tag v5.14.0 first-hand. The vulnerable helper is short enough to quote in full:
function extractTarget(toolName, toolInput) {
if (!toolInput) return toolName;
const candidates = ['command', 'file_path', 'filePath', 'path',
'url', 'query', 'pattern', 'prompt'];
for (const key of candidates) {
const v = toolInput[key];
if (typeof v === 'string' && v.length > 0) return v.slice(0, 500);
}
...
}
Both defects are visible in those eight lines: the loop returns at the first non-empty candidate (so content, new_string and every MCP tool parameter are never inspected), and the return value is sliced to 500 characters (so anything past the cut still executes). The caller, matchesAny, then tests the operator’s patterns against the tool name and that one string only. The August fix removed the truncation for matching; the October fix removed the first-field-only inspection. Each fix closed the exact hole the previous CVE named, and neither fix noticed the other hole in the same expression.
The fixed file at v5.15.2 — grown from 376 to 542 lines — is unusually honest about its own history. The replacement helpers cite the advisory IDs in their comments: extractFullTarget carries a “MUST NOT be truncated” warning referencing GHSA-743h-jr5x-mpcr (the August truncation record), collectInputStrings recursively gathers every string in the tool input so a payload “cannot hide behind a benign primary field” referencing GHSA-9p2w-prp8-5722 (this batch’s record), and the old 500-character cut survives only as truncateForDisplay, marked display-only with an explicit “never use this output for security matching”. The fix also adds pattern hardening the CVEs never asked for: a 512-character cap on pattern sources and a nested-quantifier check against ReDoS. That is what a guardrail rewrite looks like when the author has been burned twice by the same function.
The other two are the same mistake at different layers
We verified both companions in the v5.14.0 sources. DashboardServer.handleUpgrade in lib/dashboard-server.ts checks exactly one thing before completing the WebSocket handshake: that the sec-websocket-key header is present. That header is a protocol nonce, not a secret — every cross-site request can carry one — so there is no Origin check and no token check between a malicious page and the live agent-topology stream. The SSE flaw is the subtler twin: _handleRequest in lib/mcp-transport-sse.ts reflects any localhost-shaped Origin, and the non-loopback case gets only a stderr warning plus “bearer auth on tool calls” — which does nothing for the endpoints that deliberately take no auth, like /health. The v5.15.2 code gates the reflection on a loopback bind with a comment citing GHSA-4pvg-m42h-c3x2. The pattern across all three October records is one the maintainers would probably now state themselves: a check that assumes the caller’s context instead of verifying it — the first field stands in for the whole input, key presence stands in for authentication, a localhost Origin stands in for same-host.
Disclosure timeline worth noting
This batch is the well-behaved kind. Release v5.15.2 shipped 27 September 2026 at 20:39:30Z; the three GitHub advisories (GHSA-9p2w-prp8-5722, GHSA-hr6v-mfxm-4438, GHSA-4pvg-m42h-c3x2, rated high, medium and low) were published within two minutes of the release; the CVEs followed on 12 October, fifteen days later. The current release is v5.15.4 (29 September). Compare that with the batches this site keeps documenting where advisories name versions that were never published: here the fixed version existed before the advisory, and the advisory existed before the CVE. Sixteen advisories now sit on the repository — this is a maintainer pair that discloses, which is also why the repeated-bypass history is visible at all instead of buried.
What to do
- Upgrade to at least 5.15.2 (5.15.4 is current). Every October CVE in this batch, and the August truncation bypass, is closed there. This is the whole remediation for the two origin/transport issues.
- Re-read your ClaudeHookBridge deny patterns after upgrading. Pre-5.15.2, a pattern you tested against
commandnever sawcontent; post-upgrade it matches recursively across all fields with a depth cap of 32. Patterns tuned to the old first-field behaviour (or that relied on truncation implicitly shortening matches) should be re-tested, and overly broad patterns will now match more often — fail-closed noise is the expected, correct side effect. - Treat PreToolUse hooks as what they are. This bridge is the control that decides whether a prompt-injected agent’s tool call executes. Two high-severity bypasses in two months in one helper means hook-based gating deserves the same adversarial review as any authentication boundary: test with payloads in the second field, past the length limit, nested one level deeper than the matcher looks.
- Do not expose the dashboard or the SSE transport beyond loopback without independent auth. The WebSocket hijack needs only a victim operator visiting a page; the CORS reflection only matters on non-loopback binds, which the server warns about but permits.
Verification note. All three CVE identifiers, NVD publication timestamps (12 October 2026, 17:17:28Z–17:17:29Z), CVSS 4.0 and 3.1 scores, CWE assignments, affected-version ranges and the VulnCheck source identifier were read first-hand from the NVD 2.0 API, as were CVE-2026-73614’s fields (13 August 2026, 4.0 8.7 / 3.1 8.8, CWE-436, before 5.15.1). Advisory IDs, severities and publication timestamps (27 September 2026, 20:41:37Z–20:41:41Z) were read first-hand from the GitHub Security Advisories API for Jovancoding/Network-AI. The extractTarget/matchesAny code, candidate list, 500-character slice, handleUpgrade key-only check, and the SSE Origin-reflection branch are quoted or described from lib/claude-hooks.ts, lib/dashboard-server.ts and lib/mcp-transport-sse.ts read first-hand at tags v5.14.0 and v5.15.2 via raw.githubusercontent.com, including the fix comments citing both GHSAs. Release tags, timestamps, star/fork counts, repository description and push date were read first-hand from the GitHub API. Brave Search corroboration found only CVE-mirror pages and no analytical coverage. We did not install Network-AI, craft a bypass payload, or send requests to any deployment; the remediation guidance is our editorial analysis. We have no evidence of exploitation and imply none.
Sources:
- NVD — CVE-2026-109331, ClaudeHookBridge deny-pattern bypass via first-field-only matching (7.5 / 7.4, CWE-436, 5.14.0 through before 5.15.2)
- NVD — CVE-2026-109330, DashboardServer cross-site WebSocket hijacking (5.3 / 4.3, CWE-1385, 5.0.0 through before 5.15.2)
- NVD — CVE-2026-109332, MCP SSE transport localhost-Origin reflection (2.3 / 3.1, CWE-346, before 5.15.2)
- GHSA-9p2w-prp8-5722 — deny/allow gate inspects only first candidate field (high, published 27 September 2026)
- GHSA-hr6v-mfxm-4438 — dashboard WebSocket handshake with no Origin/auth check (medium)
- GHSA-4pvg-m42h-c3x2 — MCP SSE transport reflects localhost CORS Origin regardless of bind (low)
- VulnCheck advisory — Network-AI dashboard cross-site WebSocket hijacking (CVE-2026-109330)
- VulnCheck advisory — Network-AI MCP SSE CORS origin validation error (CVE-2026-109332)
- Jovancoding/Network-AI
lib/claude-hooks.tsatv5.14.0— first-fieldextractTargetwith 500-character slice - Jovancoding/Network-AI releases — 5.15.2 (27 September 2026), current 5.15.4