This is a trapdoor behind a trapdoor, not a front-door smash
Tenable plugin 193424 rolls up several mod_lua-adjacent flaws fixed in Apache HTTP Server 2.4.54 on 2022-06-08: CVE-2022-29404 (r:parsebody(0) can consume unbounded input and crash the process), CVE-2022-30556 (r:wsread() can expose out-of-bounds length data to Lua applications), plus narrower edge cases like CVE-2022-28614 (ap_rwrite() over-read when a Lua app reflects extremely large attacker input) and CVE-2022-28615 (very large input into ap_strcmp_match() via third-party/Lua usage). Upstream affected versions are Apache 2.4.53 and earlier, but distro backports mean many 2.4.x package builds are already fixed.
On paper, some of these CVEs inherit 7.5 HIGH CVSS because they are reachable over the network with no auth. In reality, that overstates fleet risk: an attacker usually needs mod_lua loaded, a Lua-backed route exposed, and specific dangerous function usage like r:parsebody(0) or r:wsread(). Most Apache estates never meet all three conditions, so the vendor-style severity is too hot for generic enterprise patch queues.
4 steps from start to impact.
Find a real Lua-backed endpoint
ffuf, curl, or app-specific crawling to find a route actually handled by Apache mod_lua rather than static files, PHP, proxying, or another app stack. This is the first big reality check: a vulnerable Apache version alone is not enough; the request has to land in a Lua handler that uses the affected APIs documented by Apache.- Target runs Apache HTTP Server 2.4.53 or earlier, or a package not backported for these CVEs
lua_moduleis enabled- An exposed route is mapped to a Lua handler or websocket logic
- Many enterprise Apache deployments do not load
mod_luaat all - Even with
mod_luapresent, many sites never expose Lua routes to untrusted clients - Banner/version detection cannot prove the route exists
mod_lua is loaded or that a reachable handler calls r:parsebody(0) or r:wsread().Hit the exact dangerous code path
CVE-2022-29404, the attacker needs a Lua script that calls r:parsebody(0) and accepts attacker-controlled request bodies; a simple curl/python requests loop with a large POST body is enough. For CVE-2022-30556, the route must use mod_lua websocket support and r:wsread(). For CVE-2022-28614, the application must reflect very large attacker input through r:puts()/ap_rwrite().- Lua script uses the affected function
- Request method/body/websocket path reaches that function
- Input is attacker-controlled and not constrained earlier by app logic or request limits
- This is highly implementation-specific, not a default Apache behavior
- Safer code often passes a bounded size to
r:parsebody()rather than0 - Reverse proxies, upload limits, and app validation often block the oversized inputs needed
r:parsebody(0), r:wsread(, and r:puts( in Lua files give much better signal.Trigger the failure mode
curl, wrk, or a tiny Python script to send a very large body or crafted websocket traffic. The realistic outcomes in this bundle are process crash / DoS or limited memory disclosure to the Lua application layer; this is not a straight-line unauthenticated RCE chain.- The vulnerable function executes on attacker input
- The server has enough resource pressure or parsing behavior to hit the bug
- The service is reachable repeatedly if the first request only partially degrades it
- Impact is mostly availability loss or bounded info leak, not code execution
- Modern front doors often enforce body-size limits before Apache hands data to Lua
- EDR and host monitoring will often make repeated crash loops noisy
segfault/child restart messages, and websocket handler errors in Apache logs and systemd/journal output.Convert to business impact
- The affected route is business-critical or internet-facing
- Process restarts do not immediately mask the availability issue
- Sensitive data passes through the specific Lua handler in the info-disclosure case
- Most enterprises use Apache mainly as a reverse proxy or static server, not a Lua app platform
- Impact is route-local unless the service architecture makes that route central
- No credible public evidence shows broad in-the-wild weaponization of this bundle
The supporting signals.
| In-the-wild status | No solid public evidence of active exploitation found for this mod_lua bundle, and I found no CISA KEV listing for the relevant CVEs. |
|---|---|
| KEV status | Not listed in CISA KEV as checked against the current catalog. That is a meaningful de-prioritizer for a 2022-era Apache issue. |
| PoC availability | Public writeups and mirrors indicate PoC-level material exists, especially for CVE-2022-29404, but the more important fact is that exploitation still depends on finding a Lua route that actually calls the risky API. |
| EPSS | Threat likelihood is not screaming hot. Public EPSS mirrors place the most relevant DoS issue CVE-2022-29404 at roughly 2.15% / 83.5th percentile, while companion issues like CVE-2022-30556 and CVE-2022-28614 sit well under 1%. |
| CVSS reality check | One bundled CVE (CVE-2022-30556) carries CVSS 7.5 / AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N, and CVE-2022-29404 also scores 7.5. That vector captures protocol reachability, but not the fact that mod_lua is optional and the vulnerable functions are application-specific. |
| Affected versions | Upstream says Apache HTTP Server 2.4.53 and earlier are affected for the relevant mod_lua issues fixed in 2.4.54. |
| Fixed versions | Upstream fixed in 2.4.54. Distro backports matter: Debian bullseye fixed via 2.4.54-1~deb11u1, and Ubuntu jammy fixed via 2.4.52-1ubuntu4.1 despite retaining a lower upstream-looking version string. |
| Exposure population | There is no trustworthy internet-wide census for this bug class because banner data can find Apache, but it cannot prove mod_lua loaded + exposed Lua handler + dangerous function use. That makes scanner hit counts much noisier than true exposure. |
| Disclosure timeline | Apache released 2.4.54 on 2022-06-08; NVD published CVE-2022-29404 on 2022-06-09. This is an older issue, not a fresh burn. |
| Reporter | Apache credits Ronald Crane (Zippenhop LLC) for CVE-2022-29404, CVE-2022-30556, and CVE-2022-28614. |
noisgate verdict.
The decisive factor is reachability friction: this is only dangerous when a host is not just old Apache, but is also running mod_lua and exposing a Lua handler that calls a specific vulnerable API. That sharply narrows the real exposed population, so a fleet-wide HIGH is noise for most enterprises.
Why this verdict
- Start from 7.5 on paper because the lead CVEs are unauthenticated and network-reachable in a vacuum.
- Downgrade hard for attacker position reality: the attacker still needs an exposed Lua-backed endpoint, which excludes the majority of plain Apache reverse-proxy and static-content deployments.
- Downgrade again for code-path specificity: exploitability depends on application behavior like
r:parsebody(0)orr:wsread(), not merelyhttpdbeing installed at a vulnerable version. - Keep it above IGNORE because if that exact handler exists on an internet-facing host, the crash/info-leak path is straightforward and scanner findings are still useful for targeted validation.
Why not higher?
This bundle does not present a broadly reachable default-path RCE. There is no KEV signal, no convincing public evidence of widespread exploitation, and the blast radius is usually limited to a specific Lua route or vhost rather than every Apache server with the version string.
Why not lower?
It is still an unauthenticated network issue on the subset of servers that genuinely use mod_lua in exposed paths. If your estate includes custom Lua handlers, especially upload or websocket flows, the impact can be a real service outage or data exposure and deserves validation rather than dismissal.
What to do — in priority order.
- Inventory
lua_modulefirst — Query Apache module lists and configs to separate real risk from version-only noise. For a LOW verdict there is no formal mitigation deadline; treat this as backlog hygiene and complete the inventory in the next routine web-tier review cycle. - Bound request body parsing — Replace
r:parsebody(0)with an explicit size cap and enforce front-end request size limits so oversized bodies die before they stress Lua handlers. For LOW, there is no mitigation SLA, so roll this into the next normal code/config hardening window. - Disable unused
mod_luahandlers — If the server does not need Lua-backed routes, unloadlua_moduleor remove Lua mappings from internet-facing vhosts. That eliminates the prerequisite that makes this bug family real in the first place; schedule it as backlog hygiene. - Restrict websocket Lua endpoints — Where
r:wsread()is in use, confine exposure with path ACLs, upstream auth, or internal-only routing. This especially matters for admin or niche service paths and can be handled in the next standard maintenance window.
- A generic WAF alone is not enough; valid but oversized POST bodies or websocket traffic can still reach the Lua handler unless you enforce concrete body-size and path restrictions.
- Banner hiding does nothing. The bug is in handler behavior, not server fingerprinting.
- Patching only your edge proxy will not help if the vulnerable Apache instance with
mod_luasits behind it and still processes the Lua route.
Crowdsourced verification payload.
Run this on the target Apache host with bash verify_mod_lua_193424.sh. Example: sudo bash verify_mod_lua_193424.sh. It needs read access to Apache configs and Lua scripts; root helps on hardened systems but is not strictly required.
#!/usr/bin/env bash
# verify_mod_lua_193424.sh
# Checks whether Apache hosts are plausibly exposed to Tenable plugin 193424
# Logic:
# PATCHED -> package/backport appears fixed, OR Apache >= 2.4.54, OR mod_lua not loaded
# VULNERABLE -> Apache <= 2.4.53, mod_lua loaded, and risky Lua indicators are found
# UNKNOWN -> insufficient evidence / package backport uncertain / mod_lua loaded without obvious risky code
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
status="UNKNOWN"
reason="No conclusion yet"
have_cmd() { command -v "$1" >/dev/null 2>&1; }
version_ge() {
# returns 0 if $1 >= $2 using sort -V
[ "$(printf '%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]
}
APACHECTL=""
for c in apache2ctl apachectl httpd; do
if have_cmd "$c"; then APACHECTL="$c"; break; fi
done
if [ -z "$APACHECTL" ]; then
echo "UNKNOWN - Apache control binary not found"
exit 2
fi
VER_RAW="$($APACHECTL -v 2>/dev/null | grep -Eo 'Apache/[0-9]+\.[0-9]+\.[0-9]+' | head -n1 | cut -d/ -f2)"
if [ -z "$VER_RAW" ]; then
echo "UNKNOWN - Could not determine Apache version"
exit 2
fi
MODULES="$($APACHECTL -M 2>/dev/null || true)"
if ! printf '%s\n' "$MODULES" | grep -Eq 'lua_module'; then
echo "PATCHED - mod_lua is not loaded on this host; plugin 193424 is not practically reachable"
exit 0
fi
# Distro backport checks first
if have_cmd dpkg-query; then
PKG_VER="$(dpkg-query -W -f='${Version}' apache2 2>/dev/null || true)"
if [ -n "$PKG_VER" ]; then
if dpkg --compare-versions "$PKG_VER" ge "2.4.54-1~deb11u1"; then
echo "PATCHED - Debian-family apache2 package version suggests backported fix: $PKG_VER"
exit 0
fi
if dpkg --compare-versions "$PKG_VER" ge "2.4.52-1ubuntu4.1"; then
echo "PATCHED - Ubuntu-family apache2 package version suggests backported fix: $PKG_VER"
exit 0
fi
fi
fi
if have_cmd rpm; then
RPM_NAME="$(rpm -q httpd 2>/dev/null || true)"
if [ -n "$RPM_NAME" ] && [ "$RPM_NAME" != "package httpd is not installed" ]; then
if rpm -q --changelog httpd 2>/dev/null | grep -Eq 'CVE-2022-29404|CVE-2022-30556|CVE-2022-28614|CVE-2022-28615'; then
echo "PATCHED - RPM changelog shows relevant backport(s) for mod_lua issue set"
exit 0
fi
fi
fi
# Upstream version check
if version_ge "$VER_RAW" "2.4.54"; then
echo "PATCHED - Upstream Apache version is $VER_RAW (>= 2.4.54)"
exit 0
fi
CFG_DIRS="/etc/httpd /etc/apache2 /usr/local/apache2/conf /opt"
TMP_MATCHES="$(mktemp 2>/dev/null || echo /tmp/mod_lua_193424.$$)"
: > "$TMP_MATCHES"
# Search config and Lua sources for risky indicators
find $CFG_DIRS -type f \( -name '*.conf' -o -name '*.lua' -o -name '*.inc' \) 2>/dev/null | while read -r f; do
grep -En 'Lua(MapHandler|Hook|QuickHandler|Scope)|r:parsebody\(0\)|r:wsread\(|r:puts\(' "$f" 2>/dev/null && echo "FILE::$f" >> "$TMP_MATCHES"
done >/dev/null 2>&1
# Re-run with explicit output capture because subshell piping above hides matches on some shells
MATCH_OUTPUT="$(grep -REn 'Lua(MapHandler|Hook|QuickHandler|Scope)|r:parsebody\(0\)|r:wsread\(|r:puts\(' /etc/httpd /etc/apache2 /usr/local/apache2/conf /opt 2>/dev/null | head -n 20 || true)"
if [ -n "$MATCH_OUTPUT" ]; then
if printf '%s\n' "$MATCH_OUTPUT" | grep -Eq 'r:parsebody\(0\)|r:wsread\('; then
echo "VULNERABLE - Apache $VER_RAW with mod_lua loaded and risky indicators found"
printf '%s\n' "$MATCH_OUTPUT" | sed 's/^/ /'
exit 1
fi
echo "UNKNOWN - Apache $VER_RAW with mod_lua loaded; Lua handlers present but no direct smoking-gun call found"
printf '%s\n' "$MATCH_OUTPUT" | sed 's/^/ /'
exit 2
fi
echo "UNKNOWN - Apache $VER_RAW is older than 2.4.54 and mod_lua is loaded, but no exposed risky handler usage was identified by grep"
exit 2
If you remember one thing.
2.4.x < 2.4.54. First, identify hosts with lua_module enabled and then grep for r:parsebody(0), r:wsread(), or exposed Lua handlers; most estates will discover this is scanner noise on generic reverse proxies. For this LOW reassessment there is no noisgate mitigation SLA and effectively no noisgate remediation SLA beyond backlog hygiene; document non-use and close the noise, while any internet-facing host that truly uses vulnerable mod_lua paths should be patched or code-hardened in the next normal web maintenance cycle.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.