Bußgeld-Kopfzeile

CVE-2026-9082, The Drupal PostgreSQL SQL Injection You Should Patch Before You Prove

CVE-2026-9082 is a Drupal Core SQL injection vulnerability in the database abstraction API. Drupal disclosed it in SA-CORE-2026-004 on May 20, 2026, rated it “Highly critical,” and listed affected Drupal Core ranges from 8.9.0 through multiple 10.x and 11.x branches before the fixed releases. The most important operational detail is narrow but severe: the SQL injection affects Drupal sites using PostgreSQL, and Drupal states that it can be exploited by anonymous users. Successful exploitation may lead to information disclosure and, in some cases, privilege escalation, remote code execution, or other follow-on attacks. (Drupal.org)

The advisory changed quickly. Drupal’s May 22 update says the risk score was updated because exploit attempts were being detected in the wild. That matters more to defenders than the comforting look of a Medium CVSS number. NVD had not yet provided its own full assessment at the time of review, while CISA-ADP displayed a CVSS 3.1 score of 6.5 with low confidentiality and integrity impact. Drupal’s own risk score, however, reached 23 out of 25 after exploit attempts were detected, and the vulnerability remains pre-authentication for affected PostgreSQL-backed sites. (NVD)

The right response is not to paste public exploit code into production and “see what happens.” The right response is to identify Drupal assets, confirm the database backend, map affected versions to fixed releases, patch, review logs for known route and error patterns, and perform controlled validation in an authorized environment. Public technical research has already explained the patch and confirmed anonymous paths to the vulnerable PostgreSQL query handling. That is enough to treat exposed PostgreSQL-backed Drupal installations as urgent without turning a defensive investigation into unsafe exploitation. (Suchscheinwerfer Cyber)

What security teams should do first

The first hour should be boring and disciplined. Find every Drupal deployment. Confirm whether it runs PostgreSQL. Confirm the Drupal Core version. Patch affected systems. Then look backward in logs from at least the public service announcement window on May 18, 2026 through the advisory release and the May 22 update. Drupal warned administrators before the release that exploits might be developed within hours or days, and Drupal Steward protections were mentioned as a platform-level mitigation for known vectors, not as a reason to skip upgrades. (Drupal.org)

FrageFast answerSofortige Maßnahmen
Is the site Drupal Core?Only Drupal Core deployments are relevant to this advisory.Inventory public and internal Drupal sites.
Is the database PostgreSQL?The SQL injection issue is PostgreSQL-specific.Confirm the driver in deployment config, not from memory.
Is the Drupal version in range?Affected ranges include Drupal 8.9.0 before 10.4.10, 10.5.x before 10.5.10, 10.6.x before 10.6.9, 11.0.x before 11.1.10, 11.2.x before 11.2.12, and 11.3.x before 11.3.10.Update to the fixed version for the running branch.
Is JSON:API enabled?It is one known route family, but not the only route discussed publicly.Check enabled modules and access logs.
Ist /user/login?_format=json reachable?Public research identifies it as one anonymous path to the sink.Review logs for abnormal POST traffic and 500 responses.
Is the site non-PostgreSQL?The CVE’s SQL injection does not apply, but the release also includes Symfony and Twig security updates.Still update on a normal emergency change path.
Is the branch end-of-life?Exceptional releases or best-effort patches are not a long-term security plan.Apply the emergency fix, then plan migration.

Do not wait for a perfect exploitability score. With CVE-2026-9082, the most important facts are already enough for prioritization: anonymous reachability, a core Drupal query path, PostgreSQL-backed deployments, public patch diff, public technical analysis, and official confirmation that exploit attempts are being detected. (Drupal.org)

How CVE-2026-9082 Reaches Drupal’s PostgreSQL Query Builder

Affected versions and fixed releases

Drupal’s official affected-version range is precise:

Running Drupal branchVulnerable rangeFixed targetPractical note
Drupal 11.3.xbefore 11.3.1011.3.10Supported branch. Upgrade directly.
Drupal 11.2.xbefore 11.2.1211.2.12Supported branch. Upgrade directly.
Drupal 11.1.x or 11.0.xbefore 11.1.1011.1.10Exceptional release for an end-of-life minor line. Move forward afterward.
Drupal 10.6.xbefore 10.6.910.6.9Supported branch. Upgrade directly.
Drupal 10.5.xbefore 10.5.1010.5.10Supported branch. Upgrade directly.
Drupal 10.4.x or earlier 10.xbefore 10.4.1010.4.10Exceptional release for an end-of-life minor line. Move forward afterward.
Drupal 9.xend-of-lifemanual 9.5 patch attemptBest-effort patch only. Migration should be treated as security work.
Drupal 8.9end-of-lifemanual 8.9 patch attemptBest-effort patch only. Migration should be treated as security work.

The advisory says Drupal 11.1.x, 11.0.x, 10.4.x, and earlier releases are end-of-life and do not normally receive security coverage; Drupal 8 and Drupal 9 are also end-of-life. Because of the severity of this issue, unsupported releases and patches for unsupported versions were provided as a best effort, but those unsupported versions may still contain other previously disclosed security vulnerabilities. (Drupal.org)

Pantheon’s release note states that Pantheon-hosted sites were not affected because Pantheon does not use PostgreSQL, while still recommending that site owners update to keep codebases aligned with upstream supported branches. That distinction is useful for triage: database backend determines whether the CVE-2026-9082 SQL injection path applies, but dependency updates and unsupported-branch risk still matter. (Pantheon Docs)

Why the Medium CVSS score is not the right mental model

NVD’s page for CVE-2026-9082 showed “Not Scheduled” for NVD enrichment and displayed no NVD-provided CVSS vector, while CISA-ADP displayed CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N with a 6.5 Medium score. The record still describes SQL injection in Drupal Core affecting the same version ranges listed by Drupal. (NVD)

That Medium score can mislead teams if it becomes the only prioritization input. A public Drupal site with PostgreSQL, anonymous JSON reachability, editorial workflows, user accounts, form submissions, private content, and privileged administrative roles has a different risk profile from a low-value internal demo site. Drupal’s advisory explicitly says the issue may lead to information disclosure and, in some cases, privilege escalation, remote code execution, or other attacks. Its own risk score was updated to 23 out of 25 after exploit attempts were detected. (Drupal.org)

The safer prioritization model is exposure-based:

FactorWhy it changes priority
PostgreSQL backendThe vulnerable code path is PostgreSQL-specific.
Internet exposureAnonymous requests can reach public Drupal endpoints.
JSON login route reachabilityPublic research identifies the JSON login route as one path to the vulnerable sink.
JSON:API exposurePublic research identifies JSON:API filter syntax as another path when enabled.
Sensitive data in DrupalSQL injection impact depends heavily on what the database contains and what the application database user can access.
Administrative workflowsPrivilege escalation risk is more serious when Drupal controls high-value content, accounts, or business flows.
WAF and platform protectionsUseful as a temporary layer, but not a substitute for upgrading.
Evidence of probingRepeated endpoint probes, SQLSTATE errors, and automated scanner markers raise incident-response urgency.

CVSS is useful for normalization. It is not a replacement for asset context, reachability, data sensitivity, public exploit analysis, and vendor-specific severity.

What actually broke inside Drupal

Drupal’s Database API is designed to keep SQL syntax separate from user-provided values. Drupal’s own database documentation explains that placeholders mark where literals will be inserted into a query, allowing the database to distinguish SQL syntax from user-provided values and thereby avoid SQL injection. That is the expected security model: values are bound, not concatenated into executable SQL text. (Drupal.org)

CVE-2026-9082 is interesting because it does not look like the classic “developer concatenated a username into a query string” mistake. The flaw sits in Drupal’s Entity Query and database abstraction machinery, specifically in the PostgreSQL path. Searchlight Cyber’s technical breakdown explains that Drupal’s PostgreSQL EntityQuery condition handler wraps comparisons in LOWER(...) for case-insensitive behavior, and that the vulnerable case involved attacker-controlled array keys flowing into SQL placeholder-name construction on the case-insensitive IN path. MySQL and SQLite did not enter the same PostgreSQL-specific loop. (Suchscheinwerfer Cyber)

The patch is small enough to be unsettling. The GitHub commit for SA-CORE-2026-004 changed three files, adding array_values() normalization before condition translation and changing the PostgreSQL loop to iterate over array_values($condition['value']). In plain English, Drupal now resets array keys to sequential numeric indexes before those keys can influence placeholder construction. (GitHub)

A simplified safe version of the concept looks like this:

// Unsafe pattern, simplified for explanation only.
// The problem is not the bound value itself.
// The dangerous part is allowing an attacker-controlled array key
// to influence the placeholder identifier written into SQL text.

foreach ($condition['value'] as $key => $value) {
    $placeholder = $field_prefix . $key;
    $where[] = 'LOWER(:' . $placeholder . ')';
    $args[':' . $placeholder] = $value;
}

// Safer shape.
// Keys are discarded before placeholder identifiers are generated.

foreach (array_values($condition['value']) as $key => $value) {
    $placeholder = $field_prefix . $key;
    $where[] = 'LOWER(:' . $placeholder . ')';
    $args[':' . $placeholder] = $value;
}

That snippet is not exploit code. It shows the engineering lesson: SQL injection can appear even when values are bound if untrusted structural data is allowed to shape SQL syntax. Placeholder names, field identifiers, operators, sort keys, filter paths, and array keys deserve the same suspicion as obvious string values when they influence generated SQL.

CVE-2026-9082 Exposure Triage Workflow

Why PostgreSQL is the deciding condition

Drupal says the SQL injection vulnerability only affects sites using PostgreSQL. Searchlight Cyber’s analysis explains why: PostgreSQL is case-sensitive by default, and Drupal’s PostgreSQL-specific EntityQuery override wraps both sides of certain comparisons in LOWER(...) to produce consistent case-insensitive behavior. For an IN list, the old implementation created one placeholder per value and built those placeholder identifiers using array keys that could be attacker-controlled in specific request shapes. (Drupal.org)

That PostgreSQL-only condition should not lead to sloppy triage. Many teams do not know their true backend across all environments. A production site may differ from staging. A university or public-sector Drupal fleet may include old migrations. A headless CMS deployment may have been built years ago by a contractor. A container image may be reused across tenants with different database services. The correct answer is not “we think we use MySQL.” The correct answer is a recorded finding from configuration, deployment inventory, or runtime status.

A safe local check might look like this:

# Run only on systems you administer.
# This checks for common Drupal database driver settings without printing passwords.

grep -R "['\"]driver['\"]" web/sites/*/settings.php sites/*/settings.php 2>/dev/null \
  | sed -E "s/(password|username|database)[^,]*/REDACTED/g"

A Drush-based check is often cleaner:

# Run from the Drupal project root.
drush status --fields=drupal-version,db-driver,db-host,db-name

For Composer-managed Drupal, version evidence can be collected without touching application traffic:

composer show drupal/core --no-interaction
composer show drupal/core-recommended --no-interaction 2>/dev/null || true

In CI or a read-only source checkout, use composer.lock as a supporting artifact:

jq -r '
  .packages[]
  | select(.name=="drupal/core" or .name=="drupal/core-recommended")
  | [.name, .version]
  | @tsv
' composer.lock

Those checks do not prove exploitability. They prove exposure conditions. For CVE-2026-9082, that is the correct first step.

The known anonymous paths without reproducing the exploit

Public research has identified two anonymous entry points that can reach the vulnerable PostgreSQL loop: the JSON login endpoint and JSON:API filter syntax. Searchlight Cyber states that the login variant uses /user/login?_format=json, while the JSON:API route requires the JSON:API module and flows through entity query filtering. It also notes that JSON:API is not enabled by default, but is commonly used on Drupal sites exposing content over an API. (Suchscheinwerfer Cyber)

Drupal’s JSON:API documentation says the core JSON:API module implements the JSON:API spec for Drupal entities and provides a zero-configuration, opinionated way to allow RESTful CRUD for Drupal content. It is closely tied to Drupal’s Entity and Field APIs, authentication and authorization systems, and collection routes. That connection is why filter syntax matters to this vulnerability class: filters are not just URL decoration; they can influence entity query construction. (Drupal.org)

A defender can safely check whether JSON:API is enabled without sending exploit payloads:

drush pm:list --status=enabled --type=module | grep -i jsonapi || true

A non-exploit route existence check can be limited to headers and normal application behavior:

# Replace the host with an asset you own or are explicitly authorized to test.
curl -skI "https://www.example.org/jsonapi" | head -n 20

curl -skI "https://www.example.org/user/login?_format=json" | head -n 20

Do not mistake a reachable endpoint for confirmed exploitation. The defensible exposure statement is more structured:

{
  "asset": "www.example.org",
  "cms": "Drupal",
  "drupal_core_version": "10.6.8",
  "database_driver": "pgsql",
  "public_routes_observed": [
    "/user/login?_format=json",
    "/jsonapi"
  ],
  "cve": "CVE-2026-9082",
  "status": "exposed_until_patched",
  "validation_method": "version_and_configuration_based",
  "exploit_payload_used": false
}

That is the right kind of proof for production. It is enough to drive emergency remediation without risking data corruption, service disruption, or unauthorized access.

What public scanning looked like after disclosure

Imperva reported that, after CVE-2026-9082 was released, it observed more than 15,000 attack attempts targeting almost 6,000 individual sites across 65 countries. Imperva described the activity as primarily probing and noted common patterns around JSON:API routes, crafted filter parameters, time-based checks, syntax-break probes, and automated scanner markers. (Imperva)

That reporting should be used carefully. Vendor telemetry does not prove that every Drupal site is being successfully exploited, and it does not prove compromise on your assets. It does prove that scanning moved fast enough to make passive waiting a bad strategy. It also gives defenders a practical set of log themes to review.

SignalWhere to lookWarum das wichtig istCommon false-positive source
Repeated POST requests to /user/login?_format=jsonWeb access logs, WAF logsOne public anonymous path reaches the vulnerable query flow.Mobile apps, SSO integrations, QA tests.
Complex JSON:API collection filters from unfamiliar IPsAccess logs, edge logsJSON:API filter syntax is a public research path.Legitimate decoupled front-end clients.
Spikes in HTTP 500 from JSON endpointsAccess logs, application logsSome probes may trigger backend exceptions.Application bugs, deployment errors.
PostgreSQL SQLSTATE errors near suspicious web requestsDrupal logs, PHP logs, database logsDatabase parser or binding errors can indicate probing.Other database bugs or migrations.
Automated scanner markers in request parameters or user agentsWAF and CDN logsImperva observed Nuclei-style markers in some probes.Internal vulnerability scans.
Time-delay probe behaviorWAF logs, response-time metricsAttackers often test SQLi with timing behavior.Slow backend queries or bad network paths.

Here is a safe log triage pattern for Nginx-style logs:

# Adjust paths and date windows for your environment.
# This does not send traffic. It only reviews local logs.

LOGS="/var/log/nginx/access.log*"

zgrep -Ei '(/user/login\?_format=json|/jsonapi/|/jsonapi(\?|$))' $LOGS \
  | awk '{print $1, $4, $5, $6, $7, $9, $12}' \
  | sort \
  | uniq -c \
  | sort -nr \
  | head -n 100

A second pass can look for server errors around JSON endpoints:

zgrep -Ei '(/user/login\?_format=json|/jsonapi/|/jsonapi(\?|$))' $LOGS \
  | awk '$9 ~ /^5/ {print}' \
  | head -n 200

If Drupal application logs are available through Drush, use them to inspect errors around the disclosure window:

# Example only. Narrow the time window in your SIEM or log platform.
drush watchdog:show --count=200 --severity=Error

For PostgreSQL logs, the exact location depends on distribution and hosting model. The defensive goal is not to hunt for one magic string. It is to correlate suspicious web requests, application 500s, database errors, and any unexpected account or content changes in the same time window.

How to patch safely

Drupal’s advisory says to install the latest version and lists the fixed releases for Drupal 11 and 10. It also directs Drupal 9 and 8 users to manually apply best-effort patches because those branches are end-of-life. (Drupal.org)

For Composer-managed Drupal, a typical safe update sequence starts with backups and staging:

# 1. Create a database backup.
drush sql:dump --result-file="../backup-before-cve-2026-9082.sql"

# 2. Create a code/files backup if your deployment model requires it.
tar -czf ../files-before-cve-2026-9082.tgz web/sites/default/files 2>/dev/null || true

# 3. Inspect current Drupal packages.
composer show drupal/core drupal/core-recommended drupal/core-composer-scaffold 2>/dev/null || true

Then update the relevant branch. The exact constraint depends on your project’s composer.json and branch strategy. Drupal’s Composer update documentation shows the pattern for updating to specific core versions and warns that pinning a specific version can affect future updates. It also recommends running database updates and cache rebuilds after the code update. (Drupal.org)

Examples for supported fixed versions:

# Example for Drupal 10.6.x moving to 10.6.9.
composer require \
  drupal/core-recommended:10.6.9 \
  drupal/core-composer-scaffold:10.6.9 \
  drupal/core-project-message:10.6.9 \
  --update-with-all-dependencies

drush updatedb -y
drush cache:rebuild
# Example for Drupal 11.3.x moving to 11.3.10.
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

drush updatedb -y
drush cache:rebuild

Production deployments should normally use the tested lock file produced in staging or CI:

# On production, after deploying the reviewed composer.lock:
composer install --no-dev --prefer-dist --no-interaction
drush updatedb -y
drush cache:rebuild

Drupal’s update documentation explicitly distinguishes update work in dev or staging from production deployment, recommending that production run composer install --no-dev using the changed composer.json und composer.lock, then run database updates and cache rebuilds. (Drupal.org)

A good change record should include:

{
  "cve": "CVE-2026-9082",
  "advisory": "SA-CORE-2026-004",
  "asset": "www.example.org",
  "before": {
    "drupal_core": "10.6.8",
    "database_driver": "pgsql"
  },
  "after": {
    "drupal_core": "10.6.9",
    "database_driver": "pgsql"
  },
  "updatedb_completed": true,
  "cache_rebuild_completed": true,
  "log_review_window": "2026-05-18T00:00:00Z/2026-05-22T23:59:59Z",
  "production_exploit_payloads_used": false,
  "retest_result": "version no longer in affected range"
}

That artifact is useful for engineering, compliance, incident review, and executive reporting.

Symfony and Twig updates matter even outside PostgreSQL

Drupal’s advisory says the supported-branch releases in SA-CORE-2026-004 also include coordinated upstream security updates for Symfony and Twig, and that Drupal is affected by some of those vulnerabilities. It recommends updating dependencies whether or not the SQL injection affects the site, depending on site configuration and contributed modules. It also recommends reviewing which user roles can update Twig templates, for example through Views or contributed modules. (Drupal.org)

That means a non-PostgreSQL Drupal site should not be dismissed as “done” after the database backend check. The emergency clock may be different, but the update still has security value. A good triage label would be:

Site conditionCVE-2026-9082 SQLi urgencyStill update?Reason
Drupal + PostgreSQL + affected version + public exposureHöchsteYes, immediatelyCore SQLi conditions align.
Drupal + PostgreSQL + affected version + internal onlyHochJaInternal exposure and authenticated paths still matter.
Drupal + MySQL/MariaDB/SQLite + affected core releaseLower for this SQLiJaBundled Symfony/Twig updates and general core hygiene.
Drupal 8/9 EOL + PostgreSQLHighest plus platform debtEmergency patch plus migrationBest-effort patch does not remove other EOL risk.
Drupal 7Not in affected-version rangeVerify separatelyUnsupported ecosystem and contributed modules may still carry separate risk.

Security teams often fail at this stage because they reduce the advisory to one condition. CVE-2026-9082 is PostgreSQL-specific, but the release event is broader than one backend.

WAF rules and platform protections are temporary layers

A WAF can help reduce risk while patching is underway, especially for obvious automated probes against JSON login and JSON:API filter routes. Imperva stated that its customers were protected against exploitation attempts associated with CVE-2026-9082 and described observed probing patterns. Pantheon stated that it implemented platform-level mitigations before disclosure and that its sites were not vulnerable because Pantheon does not use PostgreSQL. (Imperva)

Still, WAF coverage is not a complete fix. The vulnerable code lives in Drupal Core. WAF rules may miss variants, authenticated paths, uncommon route shapes, internal traffic, encoded parameters, or application-specific filters. WAF logs can also become noisy once scanners start copying public research.

Temporary controls should be written as short-lived compensating controls:

temporary_controls:
  cve: CVE-2026-9082
  expires_after_patch: true
  controls:
    - name: inspect_json_login_requests
      route: "/user/login?_format=json"
      action: alert_or_challenge
      notes: "Do not block known legitimate clients without testing."
    - name: inspect_jsonapi_filter_complexity
      route_prefix: "/jsonapi"
      action: rate_limit_or_alert
      notes: "Tune for decoupled front-end clients."
    - name: suppress_database_error_leakage
      layer: "application"
      action: "generic_error_response"
      notes: "Preserve detailed errors only in protected logs."
    - name: correlate_http_500_with_db_errors
      layer: "siem"
      action: "alert"
      notes: "Useful for post-disclosure scanning detection."

The control should expire after the patch is verified. Permanent mitigation is not a brittle signature. Permanent mitigation is updated Drupal Core, supported branches, least-privilege database accounts, schema validation for API filters, and monitoring that treats SQLSTATE bursts as security signals.

Incident response after patching

Post-Patch Detection Signals for CVE-2026-9082

Patching removes the known vulnerable code path, but it does not answer whether a site was probed or compromised before the update. For public PostgreSQL-backed Drupal deployments, the minimum review should cover the window from Drupal’s May 18 PSA through the May 20 advisory and the May 22 update noting exploit attempts. (Drupal.org)

A practical post-patch review should include:

BereichWhat to checkWarum
Web access logsJSON login and JSON:API requests, unusual query structures, scanner markers, 500 responses.Identifies probing and possible exploit attempts.
Drupal logsPHP exceptions, database exceptions, login anomalies, account changes.Links web requests to application behavior.
PostgreSQL logsSQLSTATE errors, syntax errors, unusual query timing, unexpected statements.Helps distinguish harmless probes from deeper impact.
User accountsNew admins, role changes, password resets, blocked user changes.Privilege escalation may not leave obvious web-shell artifacts.
Content and configurationUnexpected content edits, Views changes, Twig template changes, module enablement.Drupal compromise often appears as configuration or content manipulation.
FilesystemNew PHP files, modified .htaccess, suspicious uploads, changed module files.Follow-on RCE or web-shell activity may persist after patching.
Outbound trafficUnexpected calls from web or DB hosts.Data access or command execution may create egress traces.
BackupsLast known-good backup before suspicious activity.Required if integrity is uncertain.

A useful SQL query for Drupal user review depends on schema and version, but a basic read-only check can start with recent account changes:

-- Run only in an authorized administrative context.
-- Adjust table prefixes if your Drupal deployment uses one.

SELECT uid, name, mail, status, created, changed, access, login
FROM users_field_data
ORDER BY changed DESC
LIMIT 50;

For role assignments:

SELECT u.uid, u.name, r.roles_target_id
FROM users_field_data u
JOIN user__roles r ON u.uid = r.entity_id
ORDER BY u.uid, r.roles_target_id;

Those queries do not prove compromise. They create reviewable evidence. If suspicious account or configuration changes line up with suspicious JSON endpoint traffic and database errors, escalate to incident response. Do not treat patching as full remediation if integrity is in doubt.

Why this bug is a broader lesson about query builders

OWASP’s SQL Injection Prevention Cheat Sheet emphasizes prepared statements, stored procedures when properly constructed, allow-list validation where needed, and least privilege. It also warns that dynamic database queries using string concatenation and user-supplied input are a classic root cause of SQL injection. CVE-2026-9082 does not invalidate those lessons; it extends them. The dangerous input was not merely a value placed after WHERE name =. It was structural input influencing generated SQL syntax through array keys and placeholder identifiers. (OWASP-Spickzettel-Serie)

That is why teams should review custom Drupal code and contributed modules for structural query inputs, not just obvious raw SQL strings. Look for code where user-controlled data can influence:

Structural elementExample riskSafer pattern
Field nameUser chooses arbitrary field to filter.Map user choices to a fixed allowlist.
Sort keyUser controls ORDER BY column.Allowlist sort fields and directions.
OperatorUser controls IN, LIKE, CONTAINS, or raw fragments.Map UI choices to known operators.
Placeholder nameUser-controlled key becomes part of generated SQL text.Generate placeholders from internal counters only.
Array keyAssociative keys reach query compilation.Normalize with array_values() when keys are not meaningful.
Filter pathJSON:API-like filters traverse entity fields.Validate schema and allowed field paths.
Aggregate functionUser chooses SQL function or expression.Use fixed server-side function maps.

A defensive PHP pattern for custom modules is simple:

// Example for custom module input normalization.
// This is not a patch for Drupal Core. It shows a safer habit for custom code.

$raw_values = $request->request->all('ids');

// Reject non-array input where an array is required.
if (!is_array($raw_values)) {
    throw new \InvalidArgumentException('Expected an array of IDs.');
}

// Discard attacker-controlled keys.
$values = array_values($raw_values);

// Validate value types after key normalization.
$ids = [];
foreach ($values as $value) {
    if (!ctype_digit((string) $value)) {
        throw new \InvalidArgumentException('Invalid ID.');
    }
    $ids[] = (int) $value;
}

// Use Drupal query APIs with normalized values.
$query = \Drupal::entityQuery('node')
    ->condition('nid', $ids, 'IN')
    ->accessCheck(TRUE);

Do not copy this as a universal solution. The important habit is separating key normalization, value validation, allowed field selection, and query construction.

Least privilege limits blast radius

SQL injection risk is not only about whether an attacker can alter a query. It is also about what the database account can do when a query is altered. OWASP recommends minimizing privileges assigned to every database account, avoiding DBA or admin access for application accounts, and giving each application only the access it needs. (OWASP-Spickzettel-Serie)

For Drupal, least privilege is often harder than it sounds. The application legitimately needs broad access to its own schema. But “broad access to the Drupal schema” should not become “superuser access to the PostgreSQL server” or “access to unrelated databases.” At minimum:

-- Conceptual PostgreSQL hardening checks.
-- Run in an administrative context and adapt to your environment.

SELECT rolname, rolsuper, rolcreatedb, rolcreaterole, rolreplication
FROM pg_roles
WHERE rolname IN ('drupal_app_user');

If the Drupal application role has superuser, database creation, role creation, or replication privileges, fix that as a separate security issue. An injection vulnerability becomes much worse when the application connects as an overpowered database principal.

A practical target state:

Privilege areaSafer posture
PostgreSQL superuserNever for the Drupal application account.
Create databaseNot needed for normal runtime.
Create roleNot needed for normal runtime.
Access to other databasesAvoid. Use database-level isolation.
File system functionsRestrict where possible.
Extension managementDo not grant to app role.
Backup/export permissionsSeparate operational role from web runtime role.

CVE-2026-9082 is a patch event, but it is also a chance to reduce blast radius before the next query-builder bug.

Why Drupal history argues for speed

Tenable’s write-up places CVE-2026-9082 in a useful historical context: Drupal Core has had prior critical vulnerabilities that were added to CISA’s Known Exploited Vulnerabilities catalog, including CVE-2018-7600, CVE-2018-7602, CVE-2019-6340, and CVE-2020-13671. The Drupalgeddon vulnerabilities became examples of how quickly attackers weaponize serious Drupal flaws after disclosure. (Tenable®)

The comparison is not that CVE-2026-9082 is identical to Drupalgeddon. It is not. CVE-2026-9082 is PostgreSQL-specific and rooted in a particular query-construction path. The comparison is operational: public Drupal Core vulnerabilities attract attention quickly, and defenders should assume that proof-of-concept analysis, scanner templates, and opportunistic probing will move faster than slow maintenance windows.

CVEWhy it is relevant to CVE-2026-9082 responseDefensive lesson
CVE-2018-7600A Drupal Core RCE widely known as Drupalgeddon 2.Critical Drupal Core bugs can become mass-exploitation events quickly.
CVE-2018-7602Another Drupal Core RCE with KEV history.Patching delays become measurable exposure.
CVE-2019-6340Drupal Core arbitrary PHP code execution tied to web services conditions.API and entity-related surfaces can become high-impact paths.
CVE-2020-13671Drupal Core file extension sanitization issue with KEV history.Not every serious Drupal flaw looks like a classic injection.
CVE-2026-9082PostgreSQL-only SQL injection in database abstraction / EntityQuery handling.Query builders and abstraction layers still require structural-input discipline.

The useful question is not “is this the next Drupalgeddon?” The useful question is “will attackers scan faster than our patch process?” For PostgreSQL-backed public Drupal sites, the answer should be assumed to be yes.

Safe validation beats production exploitation

Public technical analysis includes working proofs of concept, and The Hacker News reported that Searchlight Cyber released two working PoCs. That does not mean defenders should run them against production. Production exploitation can corrupt data, trigger application errors, violate authorization boundaries, and create incident noise that looks like attacker activity. (Die Hacker-Nachrichten)

A safe validation ladder looks like this:

LevelBeweiseRisikoWhen to use
Version checkDrupal Core version is in or out of affected range.NiedrigAlways.
Backend checkDatabase driver is PostgreSQL or not.NiedrigAlways.
Route checkJSON login or JSON:API routes are reachable.NiedrigPublic exposure triage.
Log reviewSuspicious request and error patterns exist or not.NiedrigAfter advisory, before and after patch.
Staging reproductionControlled, isolated validation using vendor-safe or internal methods.MittelOnly with authorization and backups.
Production exploit attemptDirect exploit payload against live site.HochAvoid unless incident-response leadership explicitly approves a controlled test.

For most organizations, the first four levels are enough to justify patching and close the exposure. Staging can be useful for validating monitoring and WAF controls, but it must not become a way to delay production remediation.

Security teams using AI-assisted workflows should keep the same rule. Agentic testing can help inventory assets, summarize advisories, generate safe checks, preserve command output, and produce reproducible remediation records. Penligent’s public site describes an AI pentesting workflow around CVE scanning, controlled attack-chain validation, evidence-first results, and operator-controlled actions, while its related article on AI pentest tools emphasizes context, proof, and reproducible artifacts over scanner noise. (Sträflich)

That kind of workflow is relevant only when it stays inside authorization and evidence boundaries. The goal is to compress triage and retesting, not to automate unsafe payload execution against production Drupal sites.

Detection rules that do not depend on publishing payloads

A SIEM rule for CVE-2026-9082 should not require embedding exploit strings from public PoCs. It can focus on route, method, response behavior, and anomaly correlation.

A generic pseudo-rule:

title: Possible CVE-2026-9082 Drupal Probe
status: experimental
logsource:
  category: webserver
detection:
  selection_route_login:
    cs-uri-query|contains: "_format=json"
    cs-uri-stem|endswith: "/user/login"
  selection_route_jsonapi:
    cs-uri-stem|contains: "/jsonapi"
    cs-uri-query|contains: "filter"
  selection_error:
    sc-status|startswith: "5"
  condition: (selection_route_login or selection_route_jsonapi) and selection_error
fields:
  - src_ip
  - user_agent
  - cs_method
  - cs_uri_stem
  - cs_uri_query
  - sc_status
  - time_taken
falsepositives:
  - legitimate decoupled Drupal clients
  - internal security scanners
  - QA traffic
level: medium

A higher-confidence correlation adds database error signals:

title: Drupal JSON Endpoint Error Correlated With PostgreSQL Exception
status: experimental
correlation:
  web_event:
    route:
      - "/user/login"
      - "/jsonapi"
    query_contains:
      - "_format=json"
      - "filter"
    status_class: "5xx"
  app_or_db_event:
    contains:
      - "SQLSTATE"
      - "PostgreSQL"
      - "PDOException"
  time_window: "5m"
level: high

That still requires tuning. A decoupled Drupal site may legitimately send many JSON:API filters. A broken deployment may generate 500s for unrelated reasons. Internal scanners may intentionally test routes after the advisory. The rule becomes powerful when correlated with asset facts: vulnerable version, PostgreSQL backend, public exposure, and unusual source IPs.

Common mistakes during CVE-2026-9082 response

The most dangerous mistake is trying to prove the vulnerability before patching. If the site is Drupal, in an affected version range, backed by PostgreSQL, and publicly reachable, the exposure is already strong enough to act. Patch first. Prove safely afterward.

The second mistake is assuming “not PostgreSQL” means “no work.” The SQL injection path is PostgreSQL-specific, but Drupal’s release also includes Symfony and Twig security updates for supported branches. Drupal recommends updating those dependencies whether or not the SQL injection affects a particular site, depending on configuration and contributed modules. (Drupal.org)

The third mistake is treating a WAF block as remediation. WAF telemetry is helpful. It can reduce exploit pressure and create alerting. But the code path remains vulnerable until Drupal Core is updated or the best-effort patch is applied on unsupported branches.

The fourth mistake is failing to check old or forgotten Drupal instances. The advisory’s version range reaches into old branches, and Drupal 8/9 sites are end-of-life. Forgotten microsites, campaign sites, university department pages, nonprofit donation portals, and internal publishing tools are exactly the kind of assets that remain unpatched after the main web team fixes the flagship site.

The fifth mistake is ignoring database privileges. If the Drupal database account is overpowered, any SQL injection has more room to cause harm. Least privilege is not a substitute for patching, but it is one of the few controls that can reduce blast radius across classes of SQLi.

Developer lessons for Drupal modules and API filters

Custom Drupal modules should not assume that Drupal Core’s fix removes every possible query-construction risk in local code. CVE-2026-9082 is a reminder to test structural inputs explicitly.

A small PHPUnit-style concept for custom code:

public function testFilterKeysAreNotTrusted(): void {
    $input = [
        '0' => 'published',
        'unexpected_key_from_request' => 'draft',
    ];

    $normalized = array_values($input);

    $this->assertSame([0, 1], array_keys($normalized));
    $this->assertSame(['published', 'draft'], $normalized);
}

For API filters, write schema constraints:

$allowed_fields = [
    'title' => 'title',
    'created' => 'created',
    'status' => 'status',
];

$requested_field = $request->query->get('sort');

if (!isset($allowed_fields[$requested_field])) {
    throw new \InvalidArgumentException('Unsupported sort field.');
}

$field = $allowed_fields[$requested_field];

$query = \Drupal::entityQuery('node')
    ->sort($field, 'DESC')
    ->accessCheck(TRUE);

The point is not that every array needs array_values() or every filter is dangerous. The point is that keys, operators, field paths, and query metadata are not automatically safe just because values are parameterized.

A practical runbook for defenders

A compact runbook for CVE-2026-9082 can fit on one page:

1. Inventory
   - Find all Drupal assets.
   - Record owner, environment, exposure, hosting provider.

2. Confirm exposure conditions
   - Drupal Core version.
   - Database driver.
   - Public reachability.
   - JSON login and JSON:API route presence.

3. Patch
   - Move to 10.4.10, 10.5.10, 10.6.9, 11.1.10, 11.2.12, or 11.3.10 as appropriate.
   - Apply best-effort patches only as an emergency bridge for Drupal 8/9.
   - Run database updates and cache rebuilds.

4. Review logs
   - Start at least from 2026-05-18.
   - Check JSON login, JSON:API filters, 500s, SQLSTATE, scanner markers.

5. Verify
   - Confirm version no longer falls in affected range.
   - Confirm PostgreSQL-backed sites are patched.
   - Confirm no suspicious account or role changes.

6. Harden
   - Reduce database privileges.
   - Tune WAF and SIEM rules.
   - Validate API filter schemas.
   - Plan EOL migrations.

For organizations with many Drupal sites, this should become a small data pipeline rather than a spreadsheet argument. Each asset should have fields for Drupal version, database backend, exposure, patch status, log-review status, and owner signoff.

FAQ

Is CVE-2026-9082 exploitable without authentication?

  • Yes, Drupal’s official advisory says the vulnerability can be exploited by anonymous users.
  • Public technical research identified anonymous paths involving the JSON login endpoint and JSON:API filter syntax.
  • Anonymous reachability is why PostgreSQL-backed public Drupal sites should be patched before teams attempt deeper validation.
  • Do not run public exploit payloads against production just to confirm what version and configuration evidence already proves.

Does CVE-2026-9082 affect every Drupal site?

  • No. Drupal states that this SQL injection vulnerability only affects sites using PostgreSQL.
  • Drupal sites using MySQL, MariaDB, or SQLite are not affected by this specific PostgreSQL query-handler path.
  • Non-PostgreSQL sites should still apply the release because the same Drupal update includes Symfony and Twig security updates for supported branches.
  • The safest triage record should include both Drupal Core version and database backend.

Why is the score Medium in some vulnerability databases if Drupal says Highly critical?

  • NVD had not provided its own full CVSS assessment at the time of review, while CISA-ADP showed a CVSS 3.1 score of 6.5.
  • Drupal uses its own risk scoring system and rated the issue Highly critical, later updating the risk score after exploit attempts were detected.
  • The practical risk depends on exposure, PostgreSQL use, data sensitivity, database privileges, and whether suspicious probing appears in logs.
  • For public PostgreSQL-backed Drupal sites, treat the issue as urgent regardless of the Medium-looking CVSS number.

How can I check whether my Drupal site uses PostgreSQL?

  • Siehe settings.php for the configured database driver.
  • Verwenden Sie drush status --fields=drupal-version,db-driver,db-host,db-name where Drush is available.
  • Review deployment secrets, Helm charts, Terraform, platform configuration, or managed database inventory.
  • Do not rely on memory. Production, staging, and legacy sites may use different database backends.

Is JSON:API required for exploitation?

  • Public research describes JSON:API filter syntax as one path when JSON:API is enabled.
  • Public research also describes the JSON login endpoint as another anonymous path.
  • JSON:API is important for detection because many probes target /jsonapi routes and filter parameters.
  • A disabled JSON:API module lowers one route family, but it does not replace patching an affected PostgreSQL-backed Drupal Core version.

Should non-PostgreSQL Drupal sites still update?

  • Yes. The CVE-2026-9082 SQL injection path is PostgreSQL-specific, but Drupal says the same supported-branch releases include coordinated Symfony and Twig security updates.
  • Updating also keeps the site closer to supported branch baselines.
  • If a site runs an end-of-life Drupal branch, treat migration as part of the security response.
  • Non-PostgreSQL status should change urgency, not eliminate maintenance.

Can a WAF fully mitigate CVE-2026-9082?

  • A WAF can reduce exposure to known probes and provide useful telemetry.
  • It cannot guarantee coverage for all route variants, encodings, authenticated contexts, internal traffic, or future bypasses.
  • WAF rules should be treated as temporary compensating controls.
  • The durable fix is updating Drupal Core or applying the relevant best-effort patch for unsupported branches while planning migration.

What should I look for in logs after patching?

  • Repeated requests to /user/login?_format=json.
  • Unusual /jsonapi collection requests with complex filter structures.
  • HTTP 500 responses near JSON endpoint traffic.
  • PostgreSQL SQLSTATE errors correlated with suspicious web requests.
  • Scanner-like user agents or markers, especially from unfamiliar IP ranges.
  • Unexpected administrator accounts, role changes, configuration changes, content edits, or new files.

Closing judgment

CVE-2026-9082 should be handled as an exposure and evidence problem, not as a debate over whether a Medium CVSS number looks scary enough. For a PostgreSQL-backed Drupal site in an affected version range, anonymous reachability is enough to justify emergency remediation. The safest sequence is clear: identify Drupal assets, confirm PostgreSQL, update to the fixed release, review logs from the disclosure window, validate the version and configuration state, and then harden the database and API filter surface.

Do not prove this one by attacking your own production site with public payloads. Prove it the way mature security teams prove urgent web vulnerabilities: with version evidence, backend evidence, route evidence, patch evidence, log evidence, and controlled retesting that leaves a record another engineer can reproduce.

Teilen Sie den Beitrag:
Verwandte Beiträge
de_DEGerman