← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2022-36760 · CWE-444 · Disclosed 2023-01-17

Inconsistent Interpretation of HTTP Requests

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a bad seam in a custom loading dock, not a hole in every wall

CVE-2022-36760 is an HTTP request smuggling flaw in Apache HTTP Server's mod_proxy_ajp. It affects Apache HTTP Server 2.4.0 through 2.4.54, but only when the server is actually using mod_proxy_ajp to forward requests over ajp:// to a backend such as Tomcat. Plain Apache web serving, and even Apache reverse proxying over normal HTTP/HTTPS instead of AJP, are out of scope.

The 9.0 CVSS score overstates enterprise risk because it prices the *maximum* downstream impact, not the real deployment funnel. Apache itself labeled the issue moderate, which is closer to reality: exploitation needs a specific reverse-proxy architecture, a parser discrepancy that is not trivial to weaponize, and a backend where smuggled requests meaningfully bypass security logic. That's dangerous when present, but it is nowhere near a universal pre-auth internet RCE.

"This looks scary on paper, but in real estates it only bites the smaller slice still proxying to AJP."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find an Apache frontend that actually uses AJP

The attacker first needs a target where Apache is not just internet-facing, but is specifically acting as a reverse proxy with mod_proxy_ajp enabled and ajp:// backends configured. Generic Apache exposure is not enough; the vulnerable path lives in the HTTP-to-AJP translation layer. Tooling here is usually recon plus manual fingerprinting, not a one-shot internet census.
Conditions required:
  • Internet-reachable Apache HTTP Server
  • mod_proxy and mod_proxy_ajp loaded
  • A backend application server reachable through AJP
Where this breaks in practice:
  • Most Apache deployments are not using AJP at all
  • AJP is typically an internal backend protocol, so exposure must be inferred from app architecture rather than directly scanned from the edge
  • Version-only scanners overcount because config matters as much as package version
Detection/coverage: External scanners can usually flag httpd < 2.4.55, but config-aware validation must confirm proxy_ajp_module plus ajp:// usage or this finding is mostly noise.
STEP 02

Deliver an ambiguous request

The attacker sends a crafted HTTP request designed to create a parsing disagreement between Apache's front-end handling and the AJP request Apache builds for the backend. In practice this means custom raw requests using tooling like Burp Repeater or an adapted desync tool rather than commodity spray-and-pray exploitation. The goal is to leave attacker-controlled bytes positioned so the backend interprets them as a second request.
Conditions required:
  • Ability to send raw malformed HTTP requests
  • A request pattern that survives Apache normalization and reaches mod_proxy_ajp
Where this breaks in practice:
  • The CVSS vector itself marks attack complexity as high
  • Request smuggling success is highly sensitive to exact frontend/backend behavior
  • WAFs, reverse proxies, and intermediary normalizers often break the crafted payload before it becomes a useful backend desync
Detection/coverage: WAFs and reverse proxies may log malformed Content-Length or desync-like requests, but there is no universally reliable signature specific to this CVE.
STEP 03

Abuse the backend trust boundary

If the desync lands, the backend AJP server processes a smuggled request that Apache's normal routing and policy checks did not intend. The attacker is effectively trying to speak 'behind' the frontend using Apache as the courier. Tooling remains bespoke; the value comes from backend-only routes, cache poisoning opportunities, or security assumptions tied to the frontend path.
Conditions required:
  • Persistent or reusable backend connection behavior
  • A backend route or policy that behaves differently once the request is smuggled
Where this breaks in practice:
  • Many backends do not expose a high-value internal route even if smuggling works
  • Application auth still matters; smuggling is not automatic app compromise
  • Blast radius is often limited to one app path or one virtual host
Detection/coverage: Look for backend access patterns that do not line up cleanly with frontend logs, especially impossible route sequences on Tomcat-side apps.
STEP 04

Turn desync into real impact

Impact is deployment-specific: bypassing frontend path restrictions, cache poisoning, reaching admin endpoints, or confusing session handling are the realistic outcomes. The vulnerability does not inherently grant shell access; it grants request placement inside a trust boundary. That is still serious when the backend relies on the proxy for segmentation.
Conditions required:
  • Frontend and backend enforce different security assumptions
  • The targeted application has a sensitive route or trust decision behind Apache
Where this breaks in practice:
  • No built-in code execution primitive
  • Modern app auth, tenant isolation, and backend authorization checks can sharply reduce impact
  • Many enterprises already migrated away from AJP after earlier Tomcat/AJP risk episodes
Detection/coverage: App-layer logs and cache anomalies are more useful than simple CVE signatures. Network IDS will often miss the business-logic consequence even if it sees odd requests.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo strong exploitation signal. CISA KEV does not list CVE-2022-36760; in this review I found no authoritative public evidence of widespread active exploitation.
Proof-of-concept availabilityLow commodity availability. I did not find a mainstream Metasploit or Exploit-DB module for this CVE; exploitation appears to rely on custom desync crafting with generic tooling like Burp/raw sockets rather than turnkey automation.
EPSS0.0031 from the user-provided intel, which is low and consistent with niche exposure plus higher exploit complexity.
KEV statusNot KEV-listed as of this assessment. That removes one of the strongest patch-priority amplifiers.
CVSS vector reality checkCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H means unauthenticated remote reachability on paper, but it also admits High attack complexity. The C/H/I/H/A/H tail assumes a best-case victim architecture where smuggling crosses a meaningful trust boundary.
Affected footprintUpstream affected: Apache HTTP Server 2.4.0 through 2.4.54. Operationally affected: only systems with both mod_proxy and mod_proxy_ajp enabled and actually proxying to ajp:// backends.
Fixed versionsUpstream fix: 2.4.55. Backports exist: Ubuntu marks fixes in packages including 2.4.52-1ubuntu4.3 for Jammy and 2.4.41-4ubuntu3.13 for Focal, so raw upstream version comparisons create false positives.
Scanner/exposure caveatThis CVE is hard to census from the internet. Censys/Shodan-style scans can see Apache, but they cannot reliably prove mod_proxy_ajp is in the request path because AJP is backend behavior, not an edge banner.
Disclosure and reportingDisclosed: 2023-01-17. Reported to Apache: 2022-07-12. Finder: ZeddYu_Lu from Qi'anxin Research Institute of Legendsec at Qi'anxin Group.
Vendor severity mismatchImportant nuance: Apache's own advisory and oss-security post call this issue moderate, even though the common CVSS baseline circulated for the CVE is 9.0.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.8/10)

The decisive factor is deployment narrowness: this only matters on Apache estates still using mod_proxy_ajp as a frontend-to-backend bridge, which is a much smaller population than 'all Apache servers'. The second driver is that successful exploitation yields request desync into a backend trust boundary, not a universal one-packet compromise, and the observed exploitation signal is weak.

HIGH Affected version range and upstream fix version
HIGH Requirement for `mod_proxy_ajp` plus `ajp://` backend configuration
MEDIUM Public exploit availability and real-world prevalence of exploitable AJP deployments

Why this verdict

  • Baseline starts too high: the circulated 9.0 score models worst-case backend impact, but Apache itself labeled the issue *moderate*, which already hints the field reality is narrower than the CVSS headline.
  • Requires a niche attacker path: unauthenticated remote access is not enough by itself; the attacker needs an Apache frontend that is specifically using mod_proxy_ajp to an AJP backend. That sharply cuts reachable population versus generic Apache exposure.
  • Implies a post-routing trust-boundary flaw, not instant takeover: the value comes from smuggling requests past frontend assumptions into the backend. That can be serious, but only if the backend exposes a route, cache behavior, or auth decision worth abusing.
  • High-complexity parser abuse drags the score down: the exploit path depends on getting a precise frontend/backend interpretation mismatch. Modern WAFs, intermediary normalizers, and small config differences routinely break request smuggling payloads.
  • Threat intel is quiet: no KEV listing and a low EPSS (0.0031) are both downward pressure. If attackers loved this at scale, those signals would usually be louder.

Why not higher?

There is no strong evidence of widespread in-the-wild exploitation, no KEV listing, and no sign of commodity exploit operationalization. More importantly, the vulnerable population is not 'all Apache servers' but the much smaller subset still bridging to AJP backends with exploitable trust assumptions behind them.

Why not lower?

This still deserves more than backlog trivia because it is *unauthenticated and remote* once the right proxy chain exists. In estates that do use AJP, the vulnerability can punch through frontend controls and reach backend-only behavior, which is real security boundary erosion even without a native RCE primitive.

05 · Compensating Control

What to do — in priority order.

  1. Inventory AJP use — Find every Apache host that both loads proxy_ajp_module and references ajp:// in ProxyPass, BalancerMember, or included configs. For a MEDIUM verdict there is no mitigation SLA — go straight to the 365-day remediation window, but do this discovery early so you can separate real exposure from version-only scanner noise.
  2. Disable mod_proxy_ajp where unused — If the module is loaded but no live app requires AJP, remove the module and related proxy rules to collapse exposure entirely. There is no mitigation SLA for MEDIUM, so execute in the next normal change window rather than treating it like an emergency outage event.
  3. Migrate AJP backends to HTTP/HTTPS where feasible — Replace ajp:// backend links with http:// or https:// reverse proxying when the application stack supports it; that removes this entire bug class from the Apache-to-app hop. For MEDIUM, plan this within the normal engineering backlog and complete it inside the 365-day remediation window.
  4. Constrain backend trust assumptions — Review apps behind Apache that trust the frontend for path filtering, admin-route hiding, or IP-based decisions. Even before patching, reduce reliance on the proxy as the only enforcement point so a smuggled request has less value; with MEDIUM there is no mitigation SLA, but this is worthwhile hardening during routine app reviews.
  5. Tune detections for desync behavior — Alert on malformed length handling, anomalous backend route access, and frontend/backend log mismatches for AJP-backed apps. This will not prevent exploitation, but it improves visibility while you work through the remediation window.
What doesn't work
  • A version-only scanner finding does not prove exploitable exposure, because systems not using mod_proxy_ajp or using distro backports may be flagged anyway.
  • A generic perimeter WAF is not a dependable fix for request smuggling; parser discrepancies often exist precisely because different layers normalize requests differently.
  • Simply hiding the Tomcat/AJP backend from the internet does not solve this CVE, because Apache is the component ferrying the attacker-controlled request into that internal hop.
06 · Verification

Crowdsourced verification payload.

Run this on the target Apache host as root or with read access to the Apache config tree and permission to run apachectl -M/httpd -M. Save as check_cve_2022_36760.sh and run sudo bash check_cve_2022_36760.sh or sudo bash check_cve_2022_36760.sh /usr/sbin/httpd if autodetection fails.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2022_36760.sh
# Detects practical exposure to CVE-2022-36760 on Apache HTTP Server.
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -u

APACHE_BIN="${1:-}"

find_apache_bin() {
  local c
  for c in apache2 httpd apachectl apache2ctl; do
    if command -v "$c" >/dev/null 2>&1; then
      command -v "$c"
      return 0
    fi
  done
  return 1
}

ver_ge() {
  # returns 0 if $1 >= $2
  [ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]
}

have_cmd() { command -v "$1" >/dev/null 2>&1; }

if [ -z "$APACHE_BIN" ]; then
  if ! APACHE_BIN="$(find_apache_bin)"; then
    echo "UNKNOWN - could not find apache/httpd binary"
    exit 2
  fi
fi

if [ ! -x "$APACHE_BIN" ]; then
  echo "UNKNOWN - specified binary not executable: $APACHE_BIN"
  exit 2
fi

APACHE_DIRS=(/etc/apache2 /etc/httpd /usr/local/apache2/conf)
CONFIG_HITS=""
MODULES_OUT=""
VERSION_RAW=""
VERSION=""

# Best effort version discovery
VERSION_RAW="$($APACHE_BIN -v 2>/dev/null | awk -F/ '/Server version/ {print $2}' | awk '{print $1}')"
if [ -z "$VERSION_RAW" ] && have_cmd apachectl; then
  VERSION_RAW="$(apachectl -v 2>/dev/null | awk -F/ '/Server version/ {print $2}' | awk '{print $1}')"
fi
if [ -z "$VERSION_RAW" ] && have_cmd apache2ctl; then
  VERSION_RAW="$(apache2ctl -v 2>/dev/null | awk -F/ '/Server version/ {print $2}' | awk '{print $1}')"
fi
VERSION="$VERSION_RAW"

# Module listing
if "$APACHE_BIN" -M >/dev/null 2>&1; then
  MODULES_OUT="$($APACHE_BIN -M 2>/dev/null)"
elif have_cmd apachectl && apachectl -M >/dev/null 2>&1; then
  MODULES_OUT="$(apachectl -M 2>/dev/null)"
elif have_cmd apache2ctl && apache2ctl -M >/dev/null 2>&1; then
  MODULES_OUT="$(apache2ctl -M 2>/dev/null)"
fi

HAS_PROXY_AJP=0
if printf '%s' "$MODULES_OUT" | grep -qi 'proxy_ajp_module'; then
  HAS_PROXY_AJP=1
fi

# Config search for ajp usage
for d in "${APACHE_DIRS[@]}"; do
  if [ -d "$d" ]; then
    HITS=$(grep -RInE 'ajp://|proxy_ajp_module|LoadModule[[:space:]]+proxy_ajp_module' "$d" 2>/dev/null || true)
    if [ -n "$HITS" ]; then
      CONFIG_HITS+="$HITS"$'\n'
    fi
  fi
done

HAS_AJP_CONFIG=0
if [ -n "$CONFIG_HITS" ]; then
  HAS_AJP_CONFIG=1
fi

# If AJP is not in use, this CVE is not practically reachable on this host.
if [ "$HAS_PROXY_AJP" -eq 0 ] && [ "$HAS_AJP_CONFIG" -eq 0 ]; then
  echo "PATCHED - no evidence of mod_proxy_ajp or ajp:// backend usage"
  exit 0
fi

# Upstream version fixed in 2.4.55+
if [ -n "$VERSION" ] && ver_ge "$VERSION" "2.4.55"; then
  echo "PATCHED - Apache version $VERSION is upstream-fixed and AJP usage was detected"
  exit 0
fi

# Ubuntu/Debian backport handling
if have_cmd dpkg-query; then
  PKG_VER="$(dpkg-query -W -f='${Version}' apache2 2>/dev/null || true)"
  CODENAME="$(. /etc/os-release 2>/dev/null; echo ${VERSION_CODENAME:-})"
  if [ -n "$PKG_VER" ]; then
    case "$CODENAME" in
      jammy)
        if dpkg --compare-versions "$PKG_VER" ge "2.4.52-1ubuntu4.3"; then
          echo "PATCHED - Ubuntu Jammy apache2 package $PKG_VER includes the fix/backport"
          exit 0
        fi
        ;;
      focal)
        if dpkg --compare-versions "$PKG_VER" ge "2.4.41-4ubuntu3.13"; then
          echo "PATCHED - Ubuntu Focal apache2 package $PKG_VER includes the fix/backport"
          exit 0
        fi
        ;;
      bionic)
        if dpkg --compare-versions "$PKG_VER" ge "2.4.29-1ubuntu4.26"; then
          echo "PATCHED - Ubuntu Bionic apache2 package $PKG_VER includes the fix/backport"
          exit 0
        fi
        ;;
      xenial)
        if dpkg --compare-versions "$PKG_VER" ge "2.4.18-2ubuntu3.17+esm8"; then
          echo "PATCHED - Ubuntu Xenial apache2 package $PKG_VER includes the fix/backport"
          exit 0
        fi
        ;;
    esac

    # Debian and derivative packages often backport fixes without obvious upstream version numbers.
    echo "UNKNOWN - AJP usage detected and apache2 package version is $PKG_VER; verify distro backport status in vendor advisory"
    exit 2
  fi
fi

# RPM-based distros also commonly backport httpd fixes.
if have_cmd rpm && rpm -q httpd >/dev/null 2>&1; then
  RPM_VER="$(rpm -q --qf '%{VERSION}-%{RELEASE}\n' httpd 2>/dev/null || true)"
  echo "UNKNOWN - AJP usage detected and RPM package httpd-$RPM_VER may contain a backport; check vendor errata"
  exit 2
fi

# Source builds or simple upstream packages: if older than 2.4.55 and AJP is active, treat as vulnerable.
if [ -n "$VERSION" ] && ! ver_ge "$VERSION" "2.4.55"; then
  echo "VULNERABLE - Apache version $VERSION with active mod_proxy_ajp/ajp:// usage"
  exit 1
fi

echo "UNKNOWN - insufficient data to prove patched state, but AJP usage was detected"
exit 2
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, stop treating every httpd < 2.4.55 alert as a fire drill and first identify the hosts that actually use mod_proxy_ajp with ajp:// backends. For confirmed AJP frontends, either remove AJP from the path or apply the vendor-fixed/backported package during the normal cycle; for a MEDIUM verdict there is no noisgate mitigation SLA — go straight to the 365-day remediation window, and the noisgate remediation SLA is ≤ 365 days. If your scan population turns out to have no live AJP use, close the finding as configuration-inapplicable noise rather than spending patch capital like this is another internet-wormable Apache bug.

Sources

  1. Apache HTTP Server 2.4 vulnerabilities page
  2. Apache mod_proxy_ajp documentation
  3. NVD entry
  4. oss-security disclosure from Apache
  5. Ubuntu CVE tracker with backported fix versions
  6. CISA Known Exploited Vulnerabilities Catalog
  7. FIRST EPSS data and methodology
  8. Censys query language documentation
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.