Shell-based vulnerability scanner for CVE-2026-45185 (Dead.Letter) in Exim MTA. Detects use-after-free in GnuTLS builds, checks version, TLS library, and CHUNKING config. Produces JSON output for CI/CD integration.
A shell script for detecting whether a Linux system is vulnerable to CVE-2026-45185, a use-after-free in the Exim mail transfer agent that can lead to remote code execution.
Designed for use in CI/CD pipelines, configuration management tooling, and ad-hoc system audits. Produces both human-readable and machine-readable (JSON) output.
CVE-2026-45185 (alias: Dead.Letter) is a use-after-free bug in Exim's BDAT (binary data) message body parsing, triggered when TLS is handled by GnuTLS.
During TLS shutdown, Exim frees its TLS transfer buffer — but a nested BDAT
receive wrapper can still process incoming bytes and call ungetc(), writing
a single \n byte into the freed region. That one-byte write corrupts heap
allocator metadata, from which an attacker can gain further memory primitives
and achieve remote code execution.
| Property | Detail |
|---|---|
| CVE | CVE-2026-45185 |
| Alias | Dead.Letter |
| Type | Use-After-Free (CWE-416) |
| Component | Exim BDAT/CHUNKING handler (GnuTLS builds only) |
| Attack vector | Network — unauthenticated, requires only a TLS connection and CHUNKING extension |
| Affected versions | Exim 4.97 – 4.99.2, GnuTLS builds only |
| Fixed in | Exim 4.99.3 |
| Discovered by | Federico Kirschbaum, XBOW Security Lab (reported 1 May 2026) |
OpenSSL builds are not affected. The vulnerability is specific to Exim compiled with
USE_GNUTLS=yes. If your Exim links against OpenSSL, you are not vulnerable regardless of version.
The script works through a decision tree, stopping and marking the system not vulnerable as soon as a definitive safe condition is confirmed:
Check 1 — Exim presence
Searches $PATH and common install locations (/usr/sbin/exim,
/usr/sbin/exim4, /usr/local/sbin/exim). If Exim is not found, the system
is not vulnerable and the script exits immediately.
Check 2 — Exim version
Parses exim -bV output and compares against the affected range
(4.97 – 4.99.2). Versions ≥ 4.99.3 are treated as patched. Versions outside
the known range are marked not vulnerable (with a note if they are
unrecognised).
Check 3 — TLS library (the critical gate) Uses three detection methods in sequence:
exim -bV build information (most reliable — Exim reports its own compile-time features, e.g. Support for: GnuTLS)ldd shared library linkagestrings binary scan (fallback)If OpenSSL is detected → verdict flips to not vulnerable regardless of version. If GnuTLS is detected → the attack surface is confirmed present. If neither can be determined → result is inconclusive.
Check 4 — CHUNKING/BDAT config (workaround check)
Only runs if the system is still marked vulnerable at this point. Checks
whether chunking_advertise_hosts has been explicitly set to an empty value
in the Exim config, which disables BDAT advertisement and blocks the attack
vector. Handles both single-file configs and Debian's split-config layout
(/etc/exim4/conf.d/ fragments).
Note: if
chunking_advertise_hostsis absent from the config (the default), Exim advertises CHUNKING to all hosts (*). The option must be explicitly set to an empty value to disable it.
Check 5 — Informational system mitigations Does not change the verdict, but reports on factors that affect exploitability:
/proc/sys/kernel/randomize_va_space) — should be 2checksec output for the Exim binary (PIE, RELRO, stack canaries) if checksec is installedMemoryDenyWriteExecute, NoNewPrivileges, SystemCallFilter/proc filesystem (for ASLR check)grep, awk, ldd, headchecksec (optional — for binary hardening analysis)systemctl (optional — for systemd unit inspection)Debian-exim group on Debian/Ubuntu)No external dependencies are required for the core vulnerability checks.
chmod +x check_cve_2026_45185.sh
./check_cve_2026_45185.sh
| Flag | Description |
|---|---|
--json | Output results as a JSON object (see below) |
--quiet | Suppress all output; only the exit code is set |
--no-color | Disable ANSI colour codes (useful for log files) |
--help / -h | Print usage information |
| Code | Meaning |
|---|---|
0 | Not vulnerable (or a definitive safe condition was found) |
1 | Vulnerable |
2 | Inconclusive — could not determine one or more required facts; treat as potentially vulnerable |
3 | Script error or unsupported environment |
CVE-2026-45185 (Dead.Letter) — Exim Vulnerability Assessment
============================================================
[CHECK] Checking for Exim installation...
[WARN] Exim binary found: /usr/sbin/exim4
[CHECK] Checking Exim version...
Detected version: 4.99.1
[FAIL] Exim 4.99.1 is in the vulnerable range (4.97 – 4.99.2).
[CHECK] Checking TLS library linkage (GnuTLS vs OpenSSL)...
[FAIL] Exim is linked against GnuTLS — this build IS affected.
[CHECK] Checking CHUNKING (BDAT) advertisement config...
Config file: /etc/exim4/exim4.conf
[WARN] chunking_advertise_hosts is not disabled — BDAT is active (default advertises to all hosts).
Tip: add 'chunking_advertise_hosts =' (empty value) to your main config to disable BDAT as a workaround.
[CHECK] Checking system-level exploit mitigations (informational)...
[PASS] ASLR: full randomisation (randomize_va_space=2)
glibc version: 2.35 (2.32+ has stronger heap metadata checks)
[WARN] systemd: MemoryDenyWriteExecute not set — recommend adding to unit
[WARN] systemd: NoNewPrivileges not set
------------------------------------------------------------
VERDICT
------------------------------------------------------------
VULNERABLE — CVE-2026-45185
Reason: Exim version 4.99.1 is in vulnerable range 4.97–4.99.2
Recommended actions:
1. Upgrade Exim to 4.99.3 or later (primary fix)
2. As a workaround, set 'chunking_advertise_hosts =' (empty) in exim config
3. Add MemoryDenyWriteExecute=yes and NoNewPrivileges=yes to the systemd unit
4. Ensure ASLR is set to 2: echo 2 > /proc/sys/kernel/randomize_va_space
------------------------------------------------------------
--json){
"cve": "CVE-2026-45185",
"alias": "Dead.Letter",
"host": "mailserver-01",
"timestamp": "2026-05-12T17:00:00Z",
"verdict": "vulnerable",
"reason": "Exim version 4.99.1 is in vulnerable range 4.97–4.99.2",
"exit_code": 1,
"findings": {
"exim_binary": "/usr/sbin/exim4",
"exim_version": "4.99.1",
"exim_version_vulnerable": "true",
"tls_library": "gnutls",
"tls_library_detected": "gnutls",
"exim_config": "/etc/exim4/exim4.conf",
"chunking_advertised": "true",
"aslr_level": "2",
"glibc_version": "2.35"
},
"mitigations": [
"aslr=full"
]
}
- name: Check for CVE-2026-45185
run: |
chmod +x check_cve_2026_45185.sh
./check_cve_2026_45185.sh --json | tee vuln-report.json
exit $(jq '.exit_code' vuln-report.json)
- name: Upload vulnerability report
if: always()
uses: actions/upload-artifact@v4
with:
name: cve-2026-45185-report
path: vuln-report.json
check-exim-vuln:
stage: security
script:
- chmod +x check_cve_2026_45185.sh
- ./check_cve_2026_45185.sh --json > vuln-report.json
artifacts:
when: always
paths:
- vuln-report.json
allow_failure: false