← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2014-3704 · CWE-89 · Disclosed 2022-05-13

The expandArguments function in the database abstraction API in Drupal core 7

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

This is a front-door lock that also rewires the alarm panel when you jiggle it the right way

CVE-2014-3704 is the original Drupageddon bug in Drupal core 7.x. The flaw sits in the expandArguments path of Drupal's database abstraction layer and affects Drupal 7.0 through 7.31; upstream fixed it in 7.32, while distros such as Debian backported fixes into their own package versions. Because the injection is reachable through normal web requests and can be hit by anonymous users, the attacker does not need credentials, prior foothold, or social engineering.

The vendor-ish HIGH label from GHSA understates operational reality. This is not a finicky post-auth SQLi buried in an admin panel; it is a pre-auth internet-facing compromise primitive with well-documented public PoCs, automated exploitation within hours of disclosure, and practical routes to admin creation, arbitrary PHP execution, persistence, and full site takeover.

"If a public Drupal 7.31 site still exists, treat it like an exposed root shell, not just a SQLi."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find a reachable Drupal 7 target

Attackers fingerprint Drupal over HTTP using default paths, headers, changelog leakage, or behavior on standard endpoints such as user/login. Off-the-shelf tooling and commodity internet scanning make target discovery cheap. The effective weapon here is simple internet reconnaissance plus CMS fingerprinting, not bespoke tradecraft.
Conditions required:
  • Target is internet-reachable over HTTP/HTTPS
  • Site runs Drupal 7.x
  • Affected code path is still present
Where this breaks in practice:
  • Non-public admin networks and IP allowlists kill the attack before it starts
  • A reverse proxy, WAF, or CDN with aggressive request normalization can break opportunistic spray attempts
  • Some sites hide obvious version markers, forcing the attacker to move from fingerprinting to direct exploit testing
Detection/coverage: External ASM, web fingerprinting, and CMS-aware scanners usually identify Drupal; version certainty is weaker when CHANGELOG.txt and generator metadata are removed.
STEP 02

Trigger the pre-auth SQL injection

Using the public Drupageddon technique, the attacker sends crafted array keys that abuse how Drupal builds prepared statements in expandArguments. This lands as arbitrary SQL from an unauthenticated request. Public weaponization exists in SektionEins PoCs and downstream exploit implementations.
Conditions required:
  • No authentication required
  • Request reaches vulnerable Drupal PHP code intact
  • Underlying database accepts the injected query structure
Where this breaks in practice:
  • HTTP normalization or request filtering can block malformed parameter structures
  • Custom front-end routing may reduce the reliability of canned exploit paths
  • Some exploit chains are database- and endpoint-sensitive
Detection/coverage: Network signatures exist, but generic SQLi detection misses some variants; scanner coverage is good because dedicated Nmap/NSE, Metasploit, and commercial checks were published.
STEP 03

Convert SQLi into code execution or admin control

Attackers do not stop at dumping rows. The public Rapid7 Metasploit exploit/multi/http/drupal_drupageddon path uses the SQLi to either seed a malicious form-cache object for PHP execution or create an admin user, enable PHP execution paths, and trigger payload execution. In real life, that means shell, webshell, rogue admin, or all three.
Conditions required:
  • Successful SQL execution
  • Writable database state
  • Drupal runtime can consume the attacker-controlled database entries
Where this breaks in practice:
  • Hardened PHP execution settings and removed PHP filter features can break one of the public post-SQLi paths
  • Exploit reliability varies slightly by site configuration and database behavior
  • Blue teams may detect sudden admin creation or module changes if they log application events well
Detection/coverage: EDR on the web tier helps only after the attacker turns SQLi into process execution. Application logs, DB logs, and Drupal admin object changes are more useful earlier in the chain.
STEP 04

Persist and pivot from the web tier

Once code or admin access lands, the attacker can plant backdoors in code, database state, uploaded files, cron tasks, or neighboring apps on the same host. Drupal's own follow-up PSA explicitly warned that simply upgrading later would not remove backdoors. At this stage the issue is no longer 'just a web vuln'; it becomes an assume-compromise incident on the server.
Conditions required:
  • Attacker achieved admin or code execution
  • Host shares credentials, filesystems, or services with other apps
  • Persistence locations are writable
Where this breaks in practice:
  • Container isolation, immutable deployments, and short-lived nodes reduce dwell time
  • Strong EDR and file integrity monitoring can catch webshell or cron persistence
  • Single-purpose hosts limit blast radius
Detection/coverage: Post-exploitation detection is uneven. Signature tools can find some known Drupageddon artifacts, but Drupal's own cleanup guidance says absence of traces is not proof of safety.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusYes. Drupal's PSA says automated attacks began compromising unpatched Drupal 7 sites within hours of the October 15, 2014 advisory, and defenders should assume compromise if not patched by 2014-10-15 23:00 UTC.
Proof-of-concept availabilityVery high. Public weaponization includes SektionEins PoCs, the Rapid7 Metasploit module exploit/multi/http/drupal_drupageddon, and dedicated detection/exploitation logic in Nmap NSE.
EPSS94.366% (100th percentile) per GHSA, which is exactly where you'd expect a durable, internet-reachable pre-auth CMS takeover bug to sit.
KEV statusNot listed in CISA's Known Exploited Vulnerabilities catalog from the reviewed sources, but that does not mean 'not exploited' here; Drupal and third-party reporting already document real compromise activity.
CVSS / scoring realityNVD currently shows no CVSS v3.x enrichment and only a legacy CVSS v2 7.5 / AV:N/AC:L/Au:N/C:P/I:P/A:P. That legacy score undershoots real impact because public exploit chains turn the bug into site takeover and practical RCE, not mere row disclosure.
Affected versionsDrupal core 7.0 through 7.31 are vulnerable upstream. Drupal 6 is explicitly not affected.
Fixed versionsUpstream fix is Drupal 7.32. Debian lists drupal7 wheezy fixed in 7.14-2+deb7u7 and unstable fixed in 7.32-1, which matters if your inventory keys on package versions instead of app banners.
Exposure / populationThis is old, but not dead. Drupal's official usage telemetry still showed 539 sites on 7.31 on 2026-03-01, plus many more on other ancient 7.x releases; those stats are incomplete but confirm a long vulnerable tail. Malwarebytes also described using Shodan plus PublicWWW to crawl roughly 80,000 URLs and confirmed around 900 injected web properties in later Drupal compromise research.
Disclosure timelineDrupal published SA-CORE-2014-005 on 2014-10-15; GitHub added the advisory record on 2022-05-13. If you're normalizing dates in ticketing, use 2014-10-15 as the real disclosure date.
Reporter / discovererReported by Stefan Horst of SektionEins GmbH, who also published follow-up PoC material after defenders had a short patch window.
04 · The Call

noisgate verdict.

Final Verdict
UPGRADED to CRITICAL (9.9/10)

The decisive factor is attacker position: this chain starts from unauthenticated remote web access and immediately lands in a broadly weaponized CMS compromise path. There is essentially no meaningful prerequisite beyond 'the site is publicly reachable and still on vulnerable code,' and public exploitation was documented almost immediately after disclosure.

HIGH Exploitability from the public internet
HIGH Practical impact reaching admin compromise / code execution
MEDIUM Current exposed population size in 2026

Why this verdict

  • Vendor baseline was too low: GHSA says HIGH, but the actual attack starts from unauthenticated remote access on a web-facing CMS and does not require user interaction or prior foothold.
  • Exploit friction is minimal: the prerequisite is basically 'public Drupal 7.0-7.31 site.' There is no MFA gate, no internal-network requirement, no authenticated role requirement, and no chaining with another bug.
  • Weaponization was immediate and durable: Drupal's own PSA says attacks started within hours, while public PoCs and the Metasploit module made repeatable mass exploitation realistic.
  • Blast radius exceeds database theft: public exploit paths create admins, alter modules/config, and reach arbitrary PHP execution, which turns a web app bug into a server-compromise problem.
  • Exposure was historically massive and remains non-zero: Drupal had a huge install base at disclosure, and official usage data still shows a stubborn tail of ancient 7.x deployments.

Why not higher?

It is not a perfect 10.0 only because the vulnerable population in 2026 is much smaller than it was in 2014, and some modern estates have already isolated or retired legacy Drupal. Also, not every SQLi hit will cleanly produce code execution if the site is unusually hardened or fronted by aggressive request filtering.

Why not lower?

This is not a post-auth edge case or a low-reliability parser bug. The chain is pre-auth, remote, internet-facing, publicly weaponized, and historically mass-exploited, which is exactly the pattern that should stay at the top of a patch queue whenever vulnerable assets still exist.

05 · Compensating Control

What to do — in priority order.

  1. Block public reachability — Put vulnerable Drupal 7 sites behind VPN, IP allowlists, maintenance pages, or temporary reverse-proxy ACLs immediately, within hours. For this CVE, removing anonymous internet access is the single most effective compensating control because the exploit chain begins with public HTTP requests.
  2. Deploy a request-filtering rule — Add WAF or reverse-proxy rules that reject suspicious array-key parameter patterns and known Drupageddon request shapes immediately, within hours. This is not as trustworthy as fixing code, but it is valuable if change control delays the patch or if you need time to rebuild safely.
  3. Assume compromise and hunt — For any site that was exposed while vulnerable, review for rogue admin users, PHP-enabled content paths, modified modules, file drops, cron persistence, and unexplained DB changes immediately, within hours. Drupal's own follow-up guidance is blunt: patching later does not evict backdoors already planted.
  4. Segregate shared hosting risk — If the Drupal host shares credentials, databases, or filesystem access with other apps, isolate it from peers immediately, within hours. This limits the common real-world failure mode where a web compromise becomes a multi-app or same-host incident.
What doesn't work
  • Simply upgrading in place and calling it done — Drupal's PSA explicitly warns that the patch fixes the bug, not the backdoors that may already exist.
  • Relying on MFA or SSO — the exploit is pre-auth, so identity controls never enter the kill chain.
  • Database credential rotation alone — useful for cleanup, but it does not remove attacker-created admins, altered PHP content paths, or webshells on the host.
  • Assuming generic SQLi defenses in the application are enough — this bug lives in Drupal's own query-construction layer, so upstream parameterization expectations are exactly what failed.
06 · Verification

Crowdsourced verification payload.

Run this on the target Drupal host as a local auditor or through your config-management agent. Invoke it with the Drupal web root, for example: sudo bash verify-cve-2014-3704.sh /var/www/html ; root is not strictly required for a readable web root, but package checks on Debian-based systems work best with normal local shell access.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# verify-cve-2014-3704.sh
# Determine whether a local Drupal installation appears vulnerable to CVE-2014-3704.
# Outputs exactly one of: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

set -u

TARGET_ROOT="${1:-}"

ver_lt() {
  [ "$(printf '%s
%s
' "$1" "$2" | sort -V | head -n1)" != "$2" ]
}

ver_ge() {
  [ "$(printf '%s
%s
' "$1" "$2" | sort -V | head -n1)" = "$2" ]
}

print_result() {
  local status="$1"
  case "$status" in
    PATCHED) echo "PATCHED"; exit 0 ;;
    VULNERABLE) echo "VULNERABLE"; exit 1 ;;
    *) echo "UNKNOWN"; exit 2 ;;
  esac
}

# 1) Debian package backport check, if applicable.
if command -v dpkg-query >/dev/null 2>&1; then
  if dpkg-query -W -f='${Status} ${Version}\n' drupal7 2>/dev/null | grep -q '^install ok installed '; then
    PKG_VER="$(dpkg-query -W -f='${Version}' drupal7 2>/dev/null)"
    # Debian tracker fixed wheezy in 7.14-2+deb7u7 and unstable in 7.32-1.
    if dpkg --compare-versions "$PKG_VER" ge '7.14-2+deb7u7'; then
      print_result PATCHED
    else
      print_result VULNERABLE
    fi
  fi
fi

# 2) Try to locate Drupal root if not provided.
if [ -z "$TARGET_ROOT" ]; then
  for d in /var/www/html /var/www/drupal /usr/share/drupal7 /srv/www /opt/drupal; do
    if [ -f "$d/CHANGELOG.txt" ] || [ -f "$d/includes/bootstrap.inc" ]; then
      TARGET_ROOT="$d"
      break
    fi
  done
fi

if [ -z "$TARGET_ROOT" ] || [ ! -d "$TARGET_ROOT" ]; then
  print_result UNKNOWN
fi

# 3) Parse version from CHANGELOG.txt if present.
if [ -f "$TARGET_ROOT/CHANGELOG.txt" ]; then
  VER="$(grep -Eom1 'Drupal [0-9]+\.[0-9]+' "$TARGET_ROOT/CHANGELOG.txt" | awk '{print $2}')"
  if [ -n "${VER:-}" ]; then
    MAJOR="${VER%%.*}"
    if [ "$MAJOR" != "7" ]; then
      print_result PATCHED
    fi
    if ver_ge "$VER" '7.32'; then
      print_result PATCHED
    else
      print_result VULNERABLE
    fi
  fi
fi

# 4) Fallback: inspect Drupal VERSION constant if readable.
BOOTSTRAP="$TARGET_ROOT/includes/bootstrap.inc"
if [ -f "$BOOTSTRAP" ]; then
  VER="$(grep -E "define\('VERSION'" "$BOOTSTRAP" 2>/dev/null | sed -E "s/.*'([0-9]+\.[0-9]+[^']*)'.*/\1/" | head -n1)"
  if [ -n "${VER:-}" ]; then
    MAJOR="${VER%%.*}"
    if [ "$MAJOR" != "7" ]; then
      print_result PATCHED
    fi
    if ver_ge "$VER" '7.32'; then
      print_result PATCHED
    else
      print_result VULNERABLE
    fi
  fi
fi

print_result UNKNOWN
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, do not treat this as backlog hygiene. For any internet-reachable Drupal 7.0-7.31 asset, patch / mitigate immediately, within hours because there is documented real-world exploitation; that overrides the normal noisgate mitigation SLA. If you cannot take the code fix at once, pull the site off the public internet or put a blocking control in front of it within hours, then complete the actual supported upgrade or rebuild and full compromise review inside the noisgate remediation SLA for CRITICAL issues, which is ≤ 90 days—but exposed 7.31 systems should be handled as incident candidates, not routine patch tickets.

Sources

  1. Drupal advisory SA-CORE-2014-005
  2. Drupal PSA-2014-003 follow-up
  3. GitHub Advisory GHSA-f9cm-c972-9975
  4. Rapid7 Metasploit module entry
  5. SektionEins PoC write-up
  6. Debian security tracker
  7. Drupal core usage statistics
  8. Malwarebytes Drupal compromise research
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.