← Files

CVE-2026-111497 — Brotli remediation agent#

Deterministic audit, remediation and verification for CVE-2026-111497, an out-of-bounds write in the Google Brotli decoder: three shell scripts answer with a verdict, a remediation result and a verification result, and the model reads one line of each instead of exploring the host.

<!-- md-i18n:switcher -->

Read this in: English · Deutsch · 中文 · हिन्दी · Español · Русский

CVE-2026-111497 — Brotli decoder remediation agent

A deterministic detector, remediator and verifier for CVE-2026-111497 — an out-of-bounds
write in the Google Brotli decoder (c/dec/decode.c, CWE-787). Three shell scripts perform the
full audit and return a compact verdict; the language model orchestrates and reads one line
instead of exploring the host by hand.

Contents#

Wiki · Changelog · Security · Русская версия

Why this exists#

A complete Brotli audit is not a version check. It requires answering four questions per host:
which package is installed, whether the running processes still map the vulnerable decoder,
which application paths actually decode untrusted Brotli, and whether the distro backport is the
real fix rather than an unrelated rebuild.

Answered by hand, those questions cost dozens of tool calls per host and produce prose that
cannot be re-checked. Here they are answered by scripts with a fixed exit-code contract:

Command Effect on the host Output for the agent
detect.sh read-only VERDICT: SAFE|VULNERABLE|NOT_INSTALLED
remediate.sh single mutation point REMEDIATED: <old> -> <new>
verify.sh read-only VERIFY: PASS|FAIL

Exposure model#

The vulnerable code is the decoder, not the encoder. Services that only compress responses
with Brotli are not the attack surface; services that decompress untrusted Brotli are.

Reachable decode path Typical carrier
HTTP request bodies Content-Encoding: br sent to the application
Outbound HTTP clients fetch(), libcurl with CURLOPT_ENCODING set to empty (accept all)
Inbound responses from proxies Envoy/Istio HTTP decompressors
Uploaded or downloaded archives application-level Brotli streaming
Bundled runtimes Node.js, Bun, Python Brotli/brotlicffi, .NET request decompression

Vulnerable upstream releases are 1.0.3 through 1.2.0. Fixed releases are 1.0.10, 1.1.1 and
1.2.1
(shipped 21 October 2026), plus every distribution backport that references the CVE in
its packaged changelog.

Quick start#

# 1. Deliver the scripts once (host is an SSH alias from ~/.ssh/config)
scp src/common.sh src/detect.sh src/remediate.sh src/verify.sh <host>:/root/cve-2026-111497/

# 2. Audit — read-only
ssh <host> 'bash /root/cve-2026-111497/detect.sh'          # exit 0/1/3/10

# 3. Remediate — only when the verdict is VULNERABLE
ssh <host> 'bash /root/cve-2026-111497/remediate.sh'

# 4. Verify the actual effect
ssh <host> 'bash /root/cve-2026-111497/verify.sh'          # VERIFY: PASS|FAIL

Verdict and exit-code contract#

Code Verdict Meaning Next step
0 SAFE installed release is outside the vulnerable range, or a distro backport is already applied document and close
1 VULNERABLE installed upstream release is in the vulnerable range and no backport is present run remediate.sh
3 NOT_INSTALLED libbrotli1 is absent from the host document; re-check if Brotli arrives
10 ERROR precondition or invariant violated read the message, escalate, do not force
1 (verify.sh) FAIL remediation did not take effect investigate before declaring closure

remediate.sh stops with code 10 before touching the system when the apt candidate equals the
installed version, or when the candidate changelog does not reference CVE-2026-111497.

What the audit covers#

Check Mechanism Why it matters
Installed release and upstream version dpkg-query, epoch and revision stripped distro revisions hide the upstream version
Applied backport packaged changelog.Debian.gz naming the CVE the authoritative signal, not the version string
Apt candidate apt-get update then apt-cache policy decides whether a supported fix exists at all
Live consumers /proc/<pid>/maps scan for libbrotlidec a patched file does not patch a running process
Decode surface libcurl Brotli feature, Node/Bun/Python/PHP modules, ngx_brotli, mod_brotli separates decode paths from compression-only ones
Application decode primitives count of PHP files with CURLOPT_ENCODING / CURLOPT_ACCEPT_ENCODING WordPress, SimplePie and Guzzle accept every encoding, including br
Pre-patch inode snapshot find -type f -printf '%i' on the real .so the symlink inode is a false anchor

Repository layout#

src/
  common.sh      logging, version parsing, classification matrix, state_get
  detect.sh      read-only audit: verdict, JSON report, before-state
  remediate.sh   backup, authenticity gate, dry-run, install, restart, inode check
  verify.sh      version, CVE reference, stale mappings, failed units, round-trip
docs/
  THREAT-MODEL.md  decode-path exposure model and attack surface
  PLAYBOOK.md      phase-by-phase procedure for a human auditor
  FIELD-REPORT.md  anonymised results from three production hosts
wiki/             operator documentation, field cases, advisory digest
SKILL.md          agent skill: the minimal orchestration playbook
AGENTS.md         repository rules and invariants

Requirements#

Limitations#

Documentation#

Document Content
docs/THREAT-MODEL.md exposure model, decode-path inventory, severity reasoning
docs/PLAYBOOK.md the procedure the scripts implement, for a human auditor
docs/FIELD-REPORT.md three hosts, nine defects found in the field, verification evidence
Wiki field cases with root causes, advisory digest, operating runbook

Languages#

English is canonical: a document without a language suffix is the source of truth. Every
translation carries the suffix of its language and links back to the canonical file.

Language Files
English (canonical) README.md, AGENTS.md, SKILL.md, docs/*.md
Russian *.ru.md
German *.de.md
Spanish *.es.md
Chinese *.zh.md
Hindi *.hi.md

The changelog and the wiki are English-only by policy: a release log and an operator handbook are
maintained as single sources, and a translation that lags behind is worse than none.

Contributing#

Fixes and new distro backports are welcome. Read CONTRIBUTING.md first: the
exit-code contract, the backup-before-change rule and the authenticity gate are not negotiable.
Security reports follow SECURITY.md.

License#

MIT. The tool is defensive; it contains no credentials, no infrastructure identifiers and no
target addresses.