One Brotli error, five leads: how Tabiri's AI agent traced Node2Shell risk
How we turned a newly disclosed decoder flaw into safe behavioral checks, mapped the services that reached risky code, and kept the final verdict in human hands.
Edwin Kairu
Co-Founder and CEO, Tabiri Analytics
A security advisory tells you what may be wrong. It does not tell you which services actually handle the risky input or whether that path is reachable. When a new Brotli decoder flaw was disclosed, we asked Tabiri's AI penetration-testing agent to turn the advisory into safe checks for a small, authorized environment.
The agent did not exploit the flaw. It helped us determine where application endpoints appeared to pass incoming Brotli-compressed requests to a decoder and where the evidence remained uncertain. A reachable decoder is a useful lead, but it is not proof of a vulnerable version or successful code execution.
The risk was in decoding requests, not compressing responses
CVE-2026-111497, sometimes called Node2Shell, is an out-of-bounds write in the Google Brotli decoder. Node.js includes this decoder in node:zlib, so a service that decompresses attacker-controlled Brotli data may expose the decoder to the flaw. Node.js published fixed releases for the affected lines: 22.23.4, 24.22.1 and 26.12.1. Organizations still need to verify the appropriate fix for their runtime or vendor package.
One detail can easily misdirect an initial check. Accept-Encoding: br asks a server to compress its response with Brotli. That proves a response-compression capability. The risk we needed to examine was different: whether the server accepts a request marked Content-Encoding: br and decompresses the body before handling it.
The question that mattered
Does this endpoint decode untrusted Brotli request data, and what safe response behavior would show that the request reached a decoder?
Teaching the check what to look for
We gave the agent the advisory and asked it to devise non-exploit checks for authorized web interfaces. It first fingerprinted likely runtimes and application surfaces. It noted whether responses negotiated Brotli compression, but treated that as context rather than evidence of inbound decoding.
The agent then sent both a valid, ordinary Brotli-compressed request body and a malformed test body to selected POST endpoints using Content-Encoding: br. It compared the responses for decoder-specific errors or signs that decoded content reached application-level validation, repeated the check across relevant services and separated Node.js paths from other runtimes.
Fingerprint
Identify likely runtimes, web surfaces and response-compression behavior without treating a banner as proof.
Compare
Send safe valid and malformed Brotli bodies, then compare how each endpoint processes the requests.
Map
Group strong signals, potential exposure and ambiguous behavior into a reviewable investigation map.
One error exposed the path into Node.js
Across ten systems, one Node.js Express service returned the strongest signal: a malformed Brotli request produced an error stack naming BrotliDecoder in node:zlib. That was direct evidence that an incoming request reached Node.js's Brotli decoder.
Several other Node.js dashboard and API surfaces returned application-level JSON errors after receiving Brotli-encoded input. Those responses were consistent with decoding before the application rejected the content. A Python service responded identically to valid and malformed requests, so the report marked it ambiguous and called for package and middleware verification rather than forcing a conclusion.
"The stack trace did not prove Node2Shell was exploitable. It proved exactly where engineers needed to look next."
Five leads are not five confirmed vulnerabilities
The result was a focused map for deeper investigation: five Node.js application surfaces treated as potential exposure and one Python service needing additional review. Other endpoints either used different stacks or produced no evidence of a reachable Node.js Brotli decoder. That is materially more useful than a broad advisory, but it is not proof that every listed runtime used an affected build.
Response behavior cannot establish the installed Node.js or Brotli version, identify every bundled library or prove that memory corruption is exploitable in a service. Our evidence did not include exact runtime or package versions for every system, and no exploit was run. Engineers still need to inspect the actual packages, account for vendor backports, apply the appropriate fixed release and verify the patch.
Evidence has a boundary
A decoder-specific response can demonstrate a reachable data path. Only runtime inventory, package verification and remediation testing can establish whether that path contains the vulnerable code and whether the fix is complete.
What the agent changed was the speed of the question
The useful part was translation. Instead of waiting for a scanner signature to match a disclosed CVE, the agent turned the advisory's mechanism into a specific question: does this endpoint decode untrusted Brotli request data, and what response would demonstrate that? It then asked that question consistently across a mixed environment while preserving an explicit uncertain category.
This approach complements conventional scanners; it does not replace them. A scanner can identify a vulnerable runtime when it has the right feed, version data, credentials and scan path. A behavioral check helps when those conditions are missing or when reachability is the key question. In both cases, people set the scope, interpret the evidence, decide whether to isolate or patch and verify that the fix worked.
References
Safe Checks. Faster Triage. Human Judgment.
Respond faster to emerging vulnerabilities
Turn credible advisories into bounded, repeatable checks while experienced engineers retain control of validation and remediation.