Database abstraction frameworks promise that SQL injection is a solved problem. CVE-2026-9082 proves that this promise rests on the assumption that the abstraction is correct for all drivers, all input patterns, all code paths. When the abstraction fails, the fall is harder because nobody expects it.
The bug that should not exist
Drupal's Database Abstraction API exists to prevent SQL injection. It is the layer that separates developers from raw SQL, sanitizes placeholders, and guarantees that user input never becomes executable code. Except when it does.
The PostgreSQL EntityQuery condition handler processes filters via JSON:API. When an attacker sends filter[name][condition][value][]=v, PHP parses this into associative arrays where the keys are attacker-controlled. The code in Condition.php does foreach(condition['value'] as key => value) and concatenates key into the SQL placeholder name: LOWER(:db_placeholder_key).
Attacker-controlled keys in the placeholder name. This escapes the prepared grammar and injects raw SQL into the WHERE clause. The abstraction that should prevent SQL injection is exactly the SQL injection vector.
The fix: array_values(). One function. Strips the keys, forces numeric indices. The entire patch is one line. What is more revealing: the simplicity of the correction or the fragility it exposes? "Almost correct" is "completely vulnerable."
The attack path: anonymous, fast, scalable
JSON:API has been enabled by default since Drupal 8.8. The /user/login?_format=json endpoint and JSON:API filters are the two confirmed anonymous paths that reach the vulnerable code path. No authentication. No session. No privilege. Just a crafted HTTP request.
The public PoC generates HTTP 500 with SQLSTATE[HY093] — proof that the payload was concatenated into the SQL. The distance between that error and data exfiltration is short. The distance to RCE is even shorter.
In PostgreSQL, pg_execute_server_program allows COPY (SELECT ...) TO PROGRAM 'sh -c "cmd"'. Drupal's database user has elevated privileges for schema migrations. The full chain: SQL injection → dump the users table → write a PHP backdoor to the webroot → login as admin → RCE. In automation, seconds. A script traversing this chain needs no human intervention.
The numbers that matter
Imperva recorded 15,000+ attempts against approximately 6,000 sites across 65 countries in the first 48 hours. 50% of attacks concentrated in gaming and financial services — sectors where user data and financial transactions are the primary targets.
Drupal estimated that less than 5% of installations use PostgreSQL. But Drupal runs on hundreds of thousands of sites — government, universities, enterprise. 5% is still thousands of targets. And these targets tend to be the largest: governments and large organizations frequently choose PostgreSQL for compliance and licensing requirements.
CISA added the CVE to its KEV (Known Exploited Vulnerabilities) catalog. Federal deadline for remediation: May 27. When the US government sets a deadline, it is because the risk is real and exploitation is actively happening.
The discrepancy that deceives
Drupal rated this 23/25 — "Highly Critical." The description: "all non-public data accessible, all data modifiable or deletable." NVD assigned CVSS 6.5 — "Low" impact.
When the vendor says "all non-public data accessible" and NVD says "low impact," trust the vendor. NVD does not model RCE via COPY TO PROGRAM. CVSS scoring does not capture exploitation chains that cross layers — from database to operating system. This discrepancy is not academic: security teams that prioritize by CVSS will underestimate the risk. Teams that prioritize by the vendor's classification will act correctly.
We see this repeatedly in our operations: NVD scores that do not reflect exploitation reality. CVSS is an input, not a verdict. The vendor's classification, the infrastructure context, and the existence of public exploitation chains are more reliable indicators.
History repeats
Drupalgeddon 2014 (CVE-2014-3704) was in the same abstraction layer. Same result: SQL injection through the API designed to prevent SQL injection. The same broken premise. The same misplaced trust.
Twelve years later, history repeats. Not because Drupal developers are negligent — they are excellent. It repeats because the premise that an abstraction layer covers all cases is structurally fragile. Every new driver, every new input format, every new code path is an attack surface the abstraction has not tested. The fact that it works for 95% of cases does not protect the remaining 5% — and the remaining 5% may be the most critical.
The lesson is not "do not use abstractions." The lesson is: abstractions reduce risk, they do not eliminate it. And when residual risk materializes, you need an independent layer that works when the abstraction fails.
Defense in depth, not single-layer trust
The patch is necessary and urgent. But patching is reactive — you apply it after the vulnerability is discovered, after attacks begin, after CISA adds it to the KEV. The window between disclosure and remediation is where damage happens.
A WAF with SQL injection rules blocks payloads before they reach the application. It does not replace the patch, but it protects during the critical window. More importantly: it protects against the next vulnerability in the same layer. Because if history repeats every 12 years in the same API, the next abstraction failure is not a question of "if" — it is a question of "when."
At Tech86, we operate on the principle that no single protection layer is sufficient on its own. The framework abstraction is the first line. The WAF is the second. Anomaly monitoring is the third. When one fails, the others stand. That is what we call Perimeter Shielding — and it is exactly the kind of protection that CVE-2026-9082 makes undeniably necessary.
