A code-generator that trusts its grammar is like a compiler that trusts its source — yes, technically a flaw, but you fed it the bullets
CVE-2026-13500 sits in tool/src/org/antlr/v4/codegen/model/OutputFile.java inside ANTLR4's Grammar Action Block Handler. ANTLR4 is a *parser generator* — a developer build-time tool that consumes .g4 grammar files and emits parser source code in Java/C#/Python/Go/etc. The flaw (CWE-74) lets a crafted action block inside a grammar inject arbitrary code into the generated output, which then compiles into whatever target the developer is building. Affected: all ANTLR4 releases through and including 4.13.2; the runtime libraries shipped to production are *not* the target — only the antlr4 tool jar / CLI used at build time.
Vendor severity of HIGH (7.3) with AV:N/PR:N/UI:N is *technically defensible* under literal CVSS rules (a grammar file can arrive over a network), but it badly misrepresents the real exposure. There is no listening service. No production host runs the ANTLR tool. The 'attack' requires a developer or CI pipeline to voluntarily feed an attacker-supplied grammar into antlr4 -Dlanguage=… Foo.g4 — which is functionally identical to running javac on attacker source. Treat this as LOW for the fleet; the only real action item is in your dev-tooling and CI policy.
4 steps from start to impact.
Attacker authors a malicious .g4 grammar
{ … } embedded target-language snippet that ANTLR copies verbatim into generated parser code. The flaw is that OutputFile.java fails to neutralize special elements when emitting these blocks, so injected payload escapes its intended scope into the generated source file. Tooling for this is trivial: any text editor.- Public exploit / PoC referenced in the disclosure
- Knowledge of the victim's target language (Java/Go/Python/etc.)
- Grammar files are rarely consumed from untrusted parties — they're vendored into repos or pulled from known upstreams
Victim runs ANTLR4 tool against the grammar
antlr4 evil.g4 (or the Maven/Gradle/SBT antlr4 plugin) and the tool emits parser source containing the injected payload. This is the entire vulnerability — ANTLR4 itself does *not* execute the payload at codegen time; it bakes it into the generated .java/.go/.py file.- Victim must voluntarily consume the attacker grammar
- ANTLR4 ≤ 4.13.2 tool jar in build path
- No org I've ever seen pulls third-party
.g4files at build time without review - Grammars are typically committed to the repo and reviewed in PR
Generated parser is compiled and shipped
javac, go build, etc.) and linked into the application. At this point the malicious code is indistinguishable from any other legitimately-authored source the build pipeline trusts.- Build pipeline doesn't diff generated artifacts
- No SAST step over generated code
- SAST on the build output catches obvious shells/eval
- Reproducible-build attestation breaks if the grammar source is tampered post-review
Payload executes in the built application
- Built application is deployed and runs the parser code
- Blast radius limited to the one application that ingested the bad grammar
- Not a wormable / lateral-movement primitive
The supporting signals.
| In-the-wild exploitation | None observed. Not on CISA KEV. No GreyNoise tags. No reports of weaponization against build pipelines. |
|---|---|
| Public PoC | Disclosure references a *public exploit*, but no widely-circulated weaponized grammar has surfaced on GitHub or Exploit-DB as of disclosure week. |
| EPSS | 0.00311 (≈0.3%) — bottom-decile, consistent with build-tool flaws that score high on paper but never get exploited at scale. |
| KEV status | Not listed. CISA has historically declined to KEV developer build tools absent supply-chain evidence. |
| CVSS interpretation | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L = 7.3. The AV:N / UI:N combo is the misleading part — it treats 'attacker can ship a file' as 'no user interaction', which inflates this class of bug. CVSS 4.0 rescored to 6.9 (MEDIUM), which is closer to reality. |
| Affected versions | ANTLR4 tool ≤ 4.13.2 (all releases through current). Runtime libraries (antlr4-runtime jars, antlr4-python3-runtime, etc.) are NOT the vulnerable component. |
| Fixed version | No vendor fix published. Vendor was contacted pre-disclosure and *did not respond*. Treat as 0-day from vendor's POV — no patched build to track. |
| Exposure data | No listening service — Shodan/Censys/FOFA inapplicable. Real exposure population = orgs whose CI runs ANTLR4 on untrusted grammar input, which is *vanishingly rare*. |
| Disclosure | Published 2026-06-28, CWE-74. Coordinated disclosure attempt failed (vendor non-response). |
| Reporter | Reported via VulDB/CIRCL channel; not attributed to a major research org. |
noisgate verdict.
Downgraded from vendor HIGH (7.3) to LOW (3.1) because the single most decisive factor is that the affected component is a *developer build-time tool*, not a runtime service — exploitation requires the victim to voluntarily compile an attacker-supplied grammar file, which is a code-trust violation regardless of any ANTLR bug. There is no exposed attack surface on production hosts.
Why this verdict
- Build-time only: OutputFile.java lives in the
tool/source tree — the ANTLR4 *generator*, not theantlr4-runtimeshipped with applications. Your 10,000-host fleet does not run this component. - Requires voluntary grammar ingestion: Exploit assumes the victim runs
antlr4 evil.g4. Grammars are essentially source code; consuming an untrusted one is equivalent togit clone && makeon a stranger's repo. The bug is downstream of an already-broken trust decision. - Role multiplier (low-value role — developer workstation / CI runner): Chain succeeds, blast radius = one developer or one build job. No fleet pivot.
- Role multiplier (typical role — internal CI building first-party grammars): Chain *fails* — grammars are vendored, reviewed in PR, not attacker-supplied. Blast radius = zero.
- Role multiplier (high-value role — public grammar registry / SaaS that compiles user-submitted grammars): Chain succeeds, blast radius = single tenant container, contained by sandbox. Such services are <0.01% of ANTLR4 install base — does not raise the floor.
- EPSS 0.3% + no KEV + no in-the-wild reports confirm market consensus that this is not an active threat.
- CVSS
AV:N/UI:Nis artifact, not reality: The vector treats file delivery as network attack with no user action. CVSS 4.0 already corrects this to 6.9 MEDIUM; real-world severity is lower still.
Why not higher?
Not MEDIUM/HIGH because there is no production attack surface — the vulnerable code is a developer tool, and no canonical high-value-role deployment (IdP, hypervisor, EDR, CA, backup) uses ANTLR4 at runtime. The role multiplier analysis finds no role where chain success yields fleet, domain, or supply-chain impact at meaningful installed-base share.
Why not lower?
Not IGNORE because there *is* a non-trivial supply-chain edge case: organizations that build language servers, query engines, or parsers from third-party grammars (e.g., language plugins from public registries) do have a real exposure path. Worth documenting and a CI policy update, but not worth waking anyone up.
What to do — in priority order.
- Inventory ANTLR4 tool usage in CI — Grep your build configs (
pom.xml,build.gradle,package.json,setup.py, Bazel/Buck rules) forantlr4,antlr4-maven-plugin,antlr4ts-cli. You need to know *which* pipelines invoke the tool before you can scope risk. No mitigation SLA for LOW — fold into normal backlog hygiene. - Enforce that .g4 grammar files come only from trusted sources — Add a CI policy check that fails the build if a
.g4file is added or modified outside an allowlist of vendored upstream paths, without a human review label. Stops the only realistic exploitation path (untrusted grammar ingestion). - Include generated parser code in SAST scope — Most shops exclude generated code from Semgrep/CodeQL because of noise — for ANTLR-generated parsers, add a narrow ruleset that flags
Runtime.exec,eval,os.system,exec.Command, dynamic loads. Catches injected payloads at build time. - Pin ANTLR4 tool version and track upstream — If vendor publishes a fix post-disclosure (currently non-responsive), pin to the patched version. Until then, pinning to a known build avoids accidentally pulling a Trojaned distribution.
- Document risk acceptance for the LOW verdict — Compliance auditors will see vendor HIGH (7.3) and ask. Pre-empt with a one-paragraph rationale citing build-time scope and trust-boundary analysis.
- Patching runtime hosts: the
antlr4-runtimelibrary shipped with applications is not the vulnerable component — patching it does nothing. - WAF / IDS signatures: there is no network protocol to sign; the 'payload' is a grammar file consumed at build time.
- EDR on production fleet: EDR sees the result of a poisoned application *after* it's deployed; it does not stop the build-time injection.
- Disabling ANTLR runtime: would break any application using generated parsers and provides zero security benefit since runtime is not vulnerable.
Crowdsourced verification payload.
Run on each CI build runner and developer workstation that may invoke ANTLR4. Invoke as ./check_antlr4.sh — no special privileges required (reads filesystem and queries package managers). Outputs VULNERABLE if ANTLR4 tool ≤ 4.13.2 is present, PATCHED if a fixed version is found, UNKNOWN if no ANTLR4 install detected.
#!/usr/bin/env bash
# noisgate verification: CVE-2026-13500 — ANTLR4 tool code injection via grammar action block
# Detects ANTLR4 *tool* (not runtime) at version <= 4.13.2 on this host.
set -u
FIXED_VERSION="" # vendor has not published a fix as of 2026-06-30; update when available
MAX_VULN="4.13.2"
FOUND=0
VULN=0
ver_le() {
# returns 0 (true) if $1 <= $2 by version sort
[ "$1" = "$2" ] && return 0
printf '%s\n%s\n' "$1" "$2" | sort -V -C
}
check_jar() {
local jar="$1"
local v
v=$(unzip -p "$jar" META-INF/MANIFEST.MF 2>/dev/null | awk -F': ' '/Implementation-Version/{gsub(/\r/,"");print $2;exit}')
[ -z "$v" ] && v=$(echo "$jar" | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | tail -1)
if [ -n "$v" ]; then
FOUND=1
echo "[+] Found ANTLR4 tool: $jar (version $v)"
if ver_le "$v" "$MAX_VULN"; then
VULN=1
echo " -> VULNERABLE (<= $MAX_VULN)"
fi
fi
}
# 1. Common jar locations
for path in /usr/local/lib /usr/share/java /opt $HOME/.m2/repository/org/antlr $HOME/.gradle/caches; do
[ -d "$path" ] || continue
while IFS= read -r jar; do
check_jar "$jar"
done < <(find "$path" -type f \( -iname 'antlr-4*.jar' -o -iname 'antlr4-4*.jar' -o -iname 'antlr4-tool-*.jar' \) 2>/dev/null)
done
# 2. npm antlr4ts-cli / antlr4-tool
if command -v npm >/dev/null 2>&1; then
for pkg in antlr4ts-cli antlr4-tool antlr4; do
v=$(npm ls -g --depth=0 "$pkg" 2>/dev/null | grep -oE "$pkg@[0-9.]+" | cut -d@ -f2)
if [ -n "$v" ]; then
FOUND=1
echo "[+] Found npm $pkg@$v"
ver_le "$v" "$MAX_VULN" && { VULN=1; echo " -> VULNERABLE"; }
fi
done
fi
# 3. pip antlr4-tools
if command -v pip >/dev/null 2>&1; then
v=$(pip show antlr4-tools 2>/dev/null | awk '/^Version:/{print $2}')
if [ -n "$v" ]; then
FOUND=1
echo "[+] Found pip antlr4-tools $v"
ver_le "$v" "$MAX_VULN" && { VULN=1; echo " -> VULNERABLE"; }
fi
fi
# 4. antlr4 on PATH
if command -v antlr4 >/dev/null 2>&1; then
v=$(antlr4 2>&1 | grep -oE 'Version [0-9.]+' | awk '{print $2}')
if [ -n "$v" ]; then
FOUND=1
echo "[+] Found antlr4 on PATH: $v"
ver_le "$v" "$MAX_VULN" && { VULN=1; echo " -> VULNERABLE"; }
fi
fi
if [ $VULN -eq 1 ]; then
echo "RESULT: VULNERABLE"
exit 2
elif [ $FOUND -eq 1 ]; then
echo "RESULT: PATCHED"
exit 0
else
echo "RESULT: UNKNOWN (no ANTLR4 tool detected on this host)"
exit 1
fi
If you remember one thing.
antlr4 *tool* jar / CLI, (2) add a CI guard that flags .g4 grammar files arriving from non-vendored paths without human review, and (3) document the risk-acceptance memo so when an auditor flags the vendor's 7.3 HIGH you have a one-paragraph rebuttal on file. Revisit only if vendor finally ships a patched build (none as of disclosure) or if you operate a service that compiles user-submitted grammars — in that narrow case, sandbox it and treat as MEDIUM.Sources
- CVE-2026-13500 — Vulnerability-Lookup (CIRCL)
- CVE-2026-13501 (sibling local injection in GoTarget) — CIRCL
- GHSA-M64J-M5C8-F58P — Vulnerability-Lookup
- CWE-74: Improper Neutralization of Special Elements ('Injection') — MITRE
- ANTLR4 project — GitHub
- antlr4 npm package — Snyk advisories
- FIRST EPSS model
- CISA KEV catalog
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.