← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-28780 · CWE-122 · Disclosed 2026-05-05

Heap-based Buffer Overflow vulnerability in mod_proxy_ajp of Apache HTTP Server

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

This is a bad loading dock, not a broken front door

CVE-2026-28780 is a heap overflow in mod_proxy_ajp that is triggered when Apache HTTP Server parses a malicious reply from an AJP backend. The key qualifier is the one the scary 9.8 summary hides: the attacker does not hit the public web listener directly and win; Apache must already be configured to use mod_proxy_ajp, and it must connect to a malicious or compromised AJP server that sends a crafted response. Apache says affected versions are through 2.4.66, fixed in 2.4.67 released on 2026-05-04.

The severity inflation comes from scoring this like a generic unauthenticated network RCE. Reality is narrower. Apache itself labeled it low on 2026-05-04/05, because the exploit path requires a trusted backend relationship, which usually means internal network reachability, a compromised app server, a rogue service registration, or a misrouted proxy target. That is still worth fixing because frontends often sit in higher-trust zones, but it is a post-initial-access or trust-boundary-pivot flaw, not an internet spray-and-pray emergency.

"This is not an internet-wide 9.8; it needs Apache to trust a malicious or already-compromised AJP backend."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Land behind the reverse proxy

The attacker first needs Apache to speak AJP to a backend they control or have compromised. In practice that means compromising a Tomcat/JBoss-style backend, poisoning service discovery/DNS, abusing config drift, or owning internal network placement so Apache connects to a rogue AJP responder. There is no evidence the public HTTP listener alone is sufficient.
Conditions required:
  • Apache is configured with mod_proxy + mod_proxy_ajp
  • At least one ajp:// backend route is configured
  • The attacker can make Apache connect to a malicious AJP server
Where this breaks in practice:
  • Many modern deployments use HTTP/HTTPS or mod_proxy_http, not AJP
  • AJP backends are usually internal-only and not attacker-controlled
  • Backend allowlists, fixed IPs, and network segmentation reduce rogue-backend scenarios
Detection/coverage: Config scanners can find proxy_ajp_module and ajp:// routes reliably; exposure scanners on the public internet are poor predictors because the vulnerable parser is on the frontend's backend connection.
STEP 02

Send a crafted AJP reply

Once Apache connects, a custom AJP responder can return a malformed packet that abuses ajp_msg_check_header() and writes 4 attacker-controlled bytes past a heap buffer. That is memory corruption, but it is a very small overwrite and occurs in a constrained parsing path, so 'RCE' is possible in theory but not the default expectation in hardened builds.
Conditions required:
  • AJP session established from Apache to attacker-controlled backend
  • Backend can speak enough AJP to keep the proxy transaction alive
Where this breaks in practice:
  • A 4-byte overwrite is materially harder to weaponize than a large arbitrary write
  • Allocator behavior, build flags, and platform hardening can turn this into a crash instead of code execution
  • No credible public exploit chain was identified in reviewed sources
Detection/coverage: Network IDS can only help if you inspect internal AJP traffic, which most teams do not. Crash telemetry, core dumps, and unusual child process exits are more realistic signals.
STEP 03

Corrupt the Apache worker

The malformed backend response lands in the Apache worker handling the proxied request. Likely outcomes are process crash, request failure, or unstable child behavior; turning that into reliable code execution depends on memory layout, process model, and available mitigations like ASLR, PIE, RELRO, and hardened allocators.
Conditions required:
  • The crafted overwrite lands in an exploitable heap state
  • The target build and runtime make the corruption useful
Where this breaks in practice:
  • Prefork/worker/event model differences change exploit stability
  • Modern Linux hardening and service supervision often collapse impact to DoS
  • Apache child-process isolation limits one-shot blast radius
Detection/coverage: EDR and service monitors should catch repeated httpd/apache2 crashes or restarts. Standard web WAFs will not see the backend-originated malicious AJP response.
STEP 04

Pivot from backend to frontend trust

If exploitation succeeds, the attacker moves from a backend trust position into the Apache frontend process, which can expose TLS material, rewrite logic, auth gates, or adjacent apps handled by that server. That trust pivot is the real risk: a compromised app tier reaching upstream into the reverse proxy tier.
Conditions required:
  • Successful memory-corruption exploitation or repeated crash condition
  • Frontend process has access to sensitive configs, keys, or routing decisions
Where this breaks in practice:
  • Requires a prior foothold or trust abuse on the backend side
  • Impact is usually limited to hosts that actually proxy over AJP
  • No KEV listing and no reviewed evidence of in-the-wild exploitation
Detection/coverage: Hunt for unexpected frontend-to-backend AJP destinations, config drift in proxy targets, and backend-originated crash clusters on Apache reverse proxies.
03 · Intelligence Metadata

The supporting signals.

In the wildNo reviewed source shows active exploitation. Not in CISA KEV as of this assessment.
Proof-of-concept availabilityI found no authoritative public PoC referenced by Apache, NVD, or CISA-adjacent sources. Treat weaponization as *possible but not demonstrated* in the open sources reviewed.
EPSS0.00026 from the user-supplied intel block, which is consistent with a very low near-term exploitation probability.
KEV statusNo. Absence from KEV matters here because this is exactly the kind of bug that looks terrifying in CVSS but has a much narrower operational path.
CVSS vector reality checkCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H assumes a generic network attacker. That overstates reachability because the attacker must control or compromise the AJP backend relationship, not merely send a web request to Apache.
Affected versionsApache says through 2.4.66 are affected; fixed in 2.4.67.
Fixed versions and backportsUpstream fix is 2.4.67. Distros are backporting independently: Ubuntu shows fixes for 26.04/24.04/22.04, Debian tracks the issue, and SUSE shows released updates for several maintained package lines.
Exposure populationInternet scanning is a weak signal for this CVE. The vulnerable parser lives on Apache's backend AJP client path, so risk is concentrated in environments that still use mod_proxy_ajp and ajp:// routes.
Disclosure timelinePublished 2026-05-05; Apache 2.4.67 released 2026-05-04; NVD/CISA ADP attached the 9.8 vector on 2026-05-06.
ResearchersCredited by Apache to Andrew Lacambra, Elhanan Haenel, Tianshuo Han, and Tristan Madani.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (4.8/10)

The decisive factor is the attacker-position requirement: this bug needs Apache to trust and connect to a malicious or already-compromised AJP backend. That sharply narrows exposed population and makes this a backend-trust pivot problem, not a broad unauthenticated internet edge compromise problem.

HIGH Downgrade from the published 9.8-style framing
MEDIUM Practical impact more often being DoS/instability than reliable RCE

Why this verdict

  • Requires backend control: the exploit path starts only if Apache connects to a malicious AJP server, which implies internal position, prior compromise, or trust abuse.
  • Reachable population is small: only hosts using mod_proxy_ajp with ajp:// backends are really in scope; plenty of Apache fleets never enable AJP at all.
  • Small overwrite, uncertain weaponization: the issue is a 4-byte attacker-controlled heap overwrite, which is serious but materially harder to convert into dependable RCE than the raw CVSS suggests.

Why not higher?

It is not higher because the public HTTP surface is not the real attack surface. The attacker must already be in a position to impersonate or compromise an AJP backend, which is compounding friction and a major reduction in exposed population. No KEV listing, no reviewed in-the-wild reports, and no authoritative public exploit chain push it further down.

Why not lower?

It is not lower because memory corruption inside a reverse proxy is never free. If you do run AJP, a compromised backend can attack the frontend process and potentially cross a trust boundary toward keys, routing logic, or adjacent applications. That keeps it out of pure backlog-hygiene territory.

05 · Compensating Control

What to do — in priority order.

  1. Disable mod_proxy_ajp where unused — If the business does not require AJP, remove the module and eliminate the vulnerable code path entirely. For a MEDIUM verdict there is noisgate mitigation SLA: no mitigation SLA — go straight to the 365-day remediation window, but unused AJP should still be removed during normal config hygiene.
  2. Pin backend targets tightly — Restrict Apache to known AJP backend IPs/hostnames and prevent dynamic or user-influenced backend selection. This reduces the chance that service-discovery poisoning, DNS drift, or a rogue internal host can become the malicious AJP peer before patching; deploy as part of normal hardening while you work the remediation window.
  3. Block rogue AJP traffic — Use host firewall rules, security groups, or ACLs so Apache can reach only sanctioned AJP backends on 8009 or your chosen port. This is the most practical containment if you must keep AJP and cannot remediate immediately.
  4. Prefer HTTP/HTTPS proxying for new deployments — Where architecture allows, move new reverse-proxy integrations off AJP and onto mod_proxy_http/HTTPS. That removes this parser family from future exposure and simplifies inspection and policy enforcement.
  5. Monitor Apache child crashes — Alert on repeated httpd/apache2 worker exits, core dumps, and backend-specific request failures on AJP-connected frontends. It will not stop exploitation, but it gives you the best chance to catch unsuccessful or DoS-style attempts while patches are pending.
What doesn't work
  • A public-edge WAF does not solve this, because the malicious payload comes back from the backend AJP server to Apache.
  • MFA is irrelevant; there is no user authentication step in the exploit chain.
  • Tomcat AJP secret helps authenticate intended peers, but it does not make a compromised legitimate backend harmless.
06 · Verification

Crowdsourced verification payload.

Run this on the target Apache host with local shell access. Invoke it as bash check_cve_2026_28780.sh or bash check_cve_2026_28780.sh /etc/apache2 if configs live in a nonstandard path; no root is required for version/module checks, but reading all config files may need elevated privileges.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_28780.sh
# Conservative detector for CVE-2026-28780 on Apache HTTP Server.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -u

CFG_ROOT="${1:-}"
STATUS="UNKNOWN"
REASON=""

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

extract_version() {
  local bin="$1"
  local out ver
  out="$($bin -v 2>/dev/null || true)"
  ver="$(printf '%s\n' "$out" | sed -n 's/^Server version: Apache\/\([0-9][0-9.]*\).*$/\1/p' | head -n1)"
  if [ -z "$ver" ]; then
    ver="$(printf '%s\n' "$out" | sed -n 's/^Server version:[[:space:]]*Apache\/\([0-9][0-9.]*\).*$/\1/p' | head -n1)"
  fi
  printf '%s' "$ver"
}

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

ver_lt() {
  # returns 0 if $1 < $2
  ! ver_ge "$1" "$2"
}

guess_cfg_roots() {
  if [ -n "$CFG_ROOT" ] && [ -d "$CFG_ROOT" ]; then
    printf '%s\n' "$CFG_ROOT"
  fi
  for d in /etc/apache2 /etc/httpd /usr/local/apache2/conf; do
    [ -d "$d" ] && printf '%s\n' "$d"
  done
}

module_loaded=0
ajp_configured=0
httpd_bin="$(find_httpd_bin || true)"
version=""

if [ -n "$httpd_bin" ]; then
  version="$(extract_version "$httpd_bin")"
fi

# Check loaded modules if possible
if [ -n "$httpd_bin" ]; then
  if "$httpd_bin" -M 2>/dev/null | grep -Eq 'proxy_ajp_module|mod_proxy_ajp'; then
    module_loaded=1
  fi
fi

# Fall back to config grep for module/config presence
while IFS= read -r root; do
  if grep -R -Eqs 'LoadModule[[:space:]]+proxy_ajp_module|proxy_ajp_module' "$root" 2>/dev/null; then
    module_loaded=1
  fi
  if grep -R -Eqs 'ajp://|ProxyPass[[:space:]].*ajp:|BalancerMember[[:space:]].*ajp:' "$root" 2>/dev/null; then
    ajp_configured=1
  fi
done < <(guess_cfg_roots)

if [ -z "$version" ]; then
  echo "UNKNOWN - Could not determine Apache httpd version"
  exit 2
fi

# Upstream fixed version
if ver_ge "$version" "2.4.67"; then
  echo "PATCHED - Apache version $version is >= 2.4.67"
  exit 0
fi

# Vulnerable code present in old version, but practical exposure depends on AJP use
if ver_lt "$version" "2.4.67"; then
  if [ "$module_loaded" -eq 1 ] && [ "$ajp_configured" -eq 1 ]; then
    echo "VULNERABLE - Apache version $version is < 2.4.67 and mod_proxy_ajp with ajp:// backend config was found"
    exit 1
  fi
  if [ "$module_loaded" -eq 1 ] || [ "$ajp_configured" -eq 1 ]; then
    echo "UNKNOWN - Apache version $version is < 2.4.67 and partial AJP indicators were found; verify distro backports and active config"
    exit 2
  fi
  echo "UNKNOWN - Apache version $version is < 2.4.67 but no active AJP module/config was detected; package may still contain vulnerable code"
  exit 2
fi

echo "UNKNOWN - Unable to classify"
exit 2
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, split your Apache fleet into two buckets: hosts that actually use mod_proxy_ajp and hosts that do not. For AJP users, validate the backend trust path, restrict AJP egress to approved backends, and plan the upgrade to 2.4.67 or vendor backports within the noisgate remediation SLA of ≤365 days for this MEDIUM finding; there is noisgate mitigation SLA — go straight to the 365-day remediation window. If a host does not use AJP, document the low practical exposure and let normal Apache update cycles pick it up.

Sources

  1. Apache HTTP Server 2.4 vulnerabilities
  2. Apache mod_proxy_ajp documentation
  3. NVD CVE-2026-28780
  4. OpenCVE record for CVE-2026-28780
  5. CISA Known Exploited Vulnerabilities Catalog
  6. Debian security tracker
  7. Ubuntu CVE tracker for apache2
  8. SUSE CVE page
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.