Era Host hosting
EraHost – Free Domain, Cheap Hosting!
Client Area
Support 24/7
Menu

CVE-2014-3704: Drupalgeddon SQL Injection Vulnerability

6 min read
11.11.2025

Vulnerability Summary

Attribute Details
Common Name Drupalgeddon
CVE Identifier CVE-2014-3704
Drupal Advisory SA-CORE-2014-005
Vulnerability Type SQL Injection (via database abstraction layer)
Affected Versions Drupal 7.x (all versions before 7.32)
Severity (CVSS v3 Base) 10.0 CRITICAL (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H)
Attack Vector Remote, unauthenticated (requires no login)
Primary Impact Full database control, data theft, PHP code execution, complete site/server compromise

Technical Description

The vulnerability resides in Drupal 7's Database Abstraction API, specifically in how it handles expanded array arguments in SQL queries through the expandArguments() function in includes/database/database.inc.

Drupalgeddon CVE-2014-3704 Analysis
Drupalgeddon — array-key injection in expandArguments() = pre-auth RCE.

For the patch-application guide (sibling), see CVE-2014-3704 — Emergency Security Patch for Drupal (Drupalgeddon). For other CMS-vuln analyses, ElFinder Cross-Site Scripting (XSS) Vulnerability.

When user-supplied input containing specially crafted nested arrays is passed to database queries, the sanitization logic fails to properly escape the content, allowing an attacker to inject arbitrary SQL syntax directly into the generated query. This bypasses Drupal's standard input filtering and prepared statement protections.

Linux VDS
High performance for your projects
  • Root access and flexible setup
  • Control panel
  • NVMe disks
  • DDR5
Linux VDS

How the Exploit Works

  1. An attacker sends a crafted HTTP request to a vulnerable Drupal site containing malicious array parameters in the query string or POST data.
  2. These parameters are passed to a database query. Due to the bug, they are not properly sanitized when converted to SQL.
  3. The malicious input alters the SQL query's structure, allowing the attacker to:
    • Add new administrator users by inserting into the users table.
    • Extract sensitive data from any database table (user emails, hashed passwords, private content).
    • Execute PHP code by inserting it into fields that get executed (like blocks or PHP input formats).
    • Modify or delete any data in the database.
# Example of a vulnerable query pattern in Drupal 7 (simplified)
$query = db_select('users', 'u')
  ->condition('uid', $input_array) // $input_array is attacker-controlled
  ->execute();

Attack URL pattern often seen in logs:

/?q=node&destination=node&uid[0][table]=users&uid[0][target]=password&uid[0][value]=1

Mitigation & Patching

Immediate Action: Update or Patch NOW

Option 1: Full Update (RECOMMENDED)

Upgrade to Drupal 7.32 or later. However, note that Drupal 7 reached End-of-Life (EOL) in January 2025 and no longer receives security updates. The long-term solution is migration to Drupal 10+.

# For composer-managed sites
composer update drupal/core --with-dependencies

# For manual updates, download and replace core files from drupal.org
# Always backup your 'sites/' directory and database first.

Option 2: Apply the Emergency Patch (If Update Is Impossible)

  1. Download the official patch:
    wget https://www.drupal.org/files/issues/SA-CORE-2014-005.patch
  2. Apply it from your Drupal root directory:
    cd /path/to/drupal
    patch -p1 < SA-CORE-2014-005.patch
  3. Clear all caches:
    drush cache-clear all
Important: The patch is a temporary fix. Due to Drupal 7's EOL status, you must immediately plan a migration to a supported CMS platform.

Temporary Access Restriction

If patching will take time, restrict site access via .htaccess (Apache) or server configuration to only trusted IPs.

# In .htaccess in Drupal root
Order deny,allow
Deny from all
Allow from 203.0.113.10  # Your IP
Allow from 192.168.1.0/24 # Your local network

Detection & Compromise Checks

If your site ran Drupal 7.x before version 7.32, assume it was compromised. Conduct thorough checks:

1. Database Investigation Queries

# Check for suspicious users created around Oct 2014
SELECT uid, name, mail, created, access FROM users WHERE created > '2014-10-14' ORDER BY created DESC;

# Look for PHP code in variables or blocks
SELECT * FROM variable WHERE value LIKE '%<?php%' OR value LIKE '%eval(%';
SELECT * FROM block WHERE body LIKE '%<?php%';

# Check for altered user roles (admin permissions)
SELECT ur.uid, u.name, r.name as role_name FROM users_roles ur JOIN users u ON ur.uid = u.uid JOIN role r ON ur.rid = r.rid WHERE r.name = 'administrator' AND u.created > '2014-10-14';

2. Filesystem Inspection

# Find recently added/modified PHP files in sites/
find /path/to/drupal/sites -name "*.php" -type f -mtime -365 -exec ls -la {} \;

# Look for common backdoor filenames
find /path/to/drupal -type f \( -name "*shell*" -o -name "*b374k*" -o -name "*c99*" -o -name "*r57*" \) 2>/dev/null

3. Web Server Log Analysis

# Search for exploit patterns in Apache/Nginx logs
grep -E "(uid\[.*\]\[table\]|expandArguments|\?q=node.*destination)" /var/log/apache2/access.log

# Look for POST requests to node endpoints with array parameters
grep "POST.*node" /var/log/apache2/access.log | head -20
If you find evidence of compromise:
  1. Take the site offline immediately.
  2. Restore from a known-clean backup from BEFORE October 15, 2014.
  3. Apply the patch or update to a clean version.
  4. Change all passwords (database, Drupal admin, SSH/FTP).
  5. Consider the server itself compromised and review other sites/services on it.

Long-Term Prevention

  1. Stay Updated: Subscribe to Drupal security announcements. For active sites, use a supported CMS version.
  2. Web Application Firewall (WAF): Deploy a WAF like Cloudflare, Sucuri, or ModSecurity to block SQL injection and other attacks at the network edge.
  3. Least Privilege Database User: Ensure Drupal's database user has only the necessary permissions (SELECT, INSERT, UPDATE, DELETE on its own database, NOT global privileges).
  4. Regular Security Scans: Use tools like the Security Review module, Acunetix, or manual penetration testing.
  5. File Integrity Monitoring: Use tools like AIDE or OSSEC to detect unauthorized file changes.

Exploitation Impact

This vulnerability had unprecedented real-world impact:

  • Mass exploitation within 7 hours: The Drupal Security Team famously stated that sites not updated within 7 hours of the announcement should be considered compromised.
  • Widespread backdooring: Thousands of sites were infected with cryptocurrency miners, spam bots, redirects to malware, and persistent backdoors.
  • Long-lasting legacy: Many unpatched or forgotten sites remained compromised for years, becoming part of botnets.
  • Highlighted supply chain risk: Compromised sites were used to distribute malware to visitors through poisoned JavaScript and iframes.
Key Takeaway: CVE-2014-3704 serves as a stark lesson in the critical importance of prompt security updates, the dangers of running end-of-life software, and the necessity of having an incident response plan for when, not if, a critical vulnerability affects your systems.
Frequently asked questions
`expandArguments()` built the SQL placeholder list from array keys without validation, on the assumption that callers pass integer keys. If an attacker controlled the array (e.g., from form input), they could supply a key that looked like a SQL fragment. The fragment got concatenated into the query — classic SQLi from "safe parameterized query." The fix added type validation on keys.
Parameter binding protects the *values*. expandArguments built the placeholder list — the part *before* binding — from untrusted input. So the SQL string itself was tainted before parameters were bound. Lesson: parameter binding only protects what you bind. Any SQL string construction from user input is still SQLi-vulnerable.
Hours. Public PoC published within 24 hours of disclosure on Oct 15, 2014. By Oct 17, automated scanners were hitting Drupal sites worldwide. Sites not patched within 7 hours of the announcement should assume compromise — that was Drupal Security Team's own guidance. The exploit was so reliable and pre-auth that even amateur attackers could weaponize it.
`grep -E '(POST.*node|GET.*destination.*uid)' access.log` finds candidate requests. Body payloads with `name[0;UPDATE` or `name[0%3BUPDATE` patterns were typical. ModSecurity rule sets added Drupalgeddon signatures within days of disclosure — if your WAF logs show "Drupalgeddon attempt" alerts, compare timestamps to your patch deployment and assume compromise for any prior hits.
Related articles
2GB Hosting: What Kind of Website Can It Handle?
What Are NS1 and NS2?
PHP mb_detect_encoding() — Supporting Multiple Encodings