
Recreating CVE-2026-9082: Testing Drupal's Query Builder for SQL Injection on PostgreSQL
Drupal's CVE-2026-9082 is not a small edge case. It is an anonymous SQL injection path in core, and on PostgreSQL-backed installs a bad query-builder assumption can turn into database execution.
What CVE-2026-9082 means for Drupal sites
The real break here is the trust boundary. Code that should have treated user input as data appears to have let a crafted request influence SQL structure on certain paths. If the vulnerable code sits in core, every site using that path inherits the exposure until it is patched.
That makes this different from a module-only flaw. For site owners, the useful question is not “does my theme use it?” but “does my core version and database backend hit the bad path?”
Why PostgreSQL-backed installs are the dangerous path
The reports around this CVE point to PostgreSQL as the high-risk backend. In practice, that usually means one of two things:
- the query builder emitted SQL that was acceptable for one database flavor but not another
- escaping or placeholder handling broke when Drupal translated higher-level query objects into PostgreSQL syntax
This is a common failure mode in abstraction layers. The app thinks it is building a parameterized query. The database driver ends up receiving a string that still contains attacker-controlled structure.
Do not assume “we use prepared statements somewhere” means the whole request path is safe. One raw fragment in a dynamic condition is enough to reopen the hole.
Recreating the bug safely in a lab
I would not validate this against a live site. Build a throwaway Drupal install, use a local PostgreSQL container, and keep the test data fake.
Build a minimal Drupal test site
Start with the smallest install that still exercises the affected query path:
- Drupal core only.
- PostgreSQL as the backend.
- One anonymous route or search-like feature that reaches the query builder.
- Debug logging enabled, but no real credentials.
The point is to reduce noise. If you can reproduce the issue in a minimal stack, the blame surface gets much clearer.
Trace the query builder output
On Drupal-like systems, I look for the moment where an input value stops being a bound parameter and starts looking like SQL text. Add logging around the final query string and the bound arguments.
A useful pattern is to compare:
- the original request parameter
- the query object before compilation
- the final SQL sent to PostgreSQL
If the dangerous input appears in the SQL string instead of the parameter array, you have your proof.
Show where parameterization breaks
function traceQuery(sql, params) {
console.log("SQL:", sql);
console.log("params:", JSON.stringify(params));
}
// Safe shape: input stays in params
traceQuery(
"SELECT * FROM nodes WHERE title ILIKE $1",
["%drupal%"]
);
// Unsafe shape: user data changes query structure
traceQuery(
"SELECT * FROM nodes WHERE title ILIKE '%drupal%' OR 1=1 --'",
[]
);That example is simplified, but the audit idea is the same: prove whether the input is bound or concatenated.
What the proof of concept likely proves
A public PoC usually tells you three things: reachability, impact, and whether the bug is reliable enough to automate.
Anonymous reachability
If the exploit works without authentication, the site is exposed at the edge. That raises urgency because no stolen session or plugin compromise is required.
SQL execution impact
With SQL injection, impact depends on database privileges. Even if the attacker cannot directly drop tables, they may still read secrets, alter content, or pivot through application data.
What to log and inspect
Look at:
- web access logs for repeated requests hitting the same Drupal path
- PostgreSQL logs for syntax errors or unusual
UNION, comment markers, or boolean probes - application logs for query exceptions on anonymous requests
If you have centralized logging, search for bursts of 400/500 responses paired with PostgreSQL syntax errors. That often shows the first probe phase of a PoC.
Patch behavior and mitigation
Update core and verify version
Apply the Drupal core update that fixes CVE-2026-9082, then verify the deployed version on every environment, not just production. I have seen “patched” app servers coexist with stale staging or failover nodes.
Reduce blast radius at the database layer
Even after patching, the database account used by Drupal should have only the privileges it needs. No superuser access, no broad schema ownership if you can avoid it, and no access to unrelated databases.
Temporary compensating controls
If you cannot patch immediately:
- restrict anonymous traffic at the edge where possible
- block suspicious request patterns before they hit Drupal
- increase PostgreSQL logging for the affected period
- disable any feature path you know is vulnerable, if the application can tolerate it
How to test your own estate for exposure
Inventory Drupal versions and database backends
Make a quick matrix:
| Site | Drupal core version | Database | Anonymous reachable | Patched |
|---|---|---|---|---|
| Marketing site | 10.x | PostgreSQL | yes | no |
| Intranet | 11.x | MySQL | no | yes |
That tells you where to focus first. PostgreSQL plus anonymous reachability is the combination I would treat as highest priority.
Search for suspicious request patterns
Look for the same endpoint receiving many requests with slight parameter variations. SQLi tooling tends to probe:
- quote handling
- boolean toggles
- comment terminators
- time-based behavior
You do not need the exact exploit string to spot the pattern.
Validate with a non-destructive probe
Use a harmless request that only confirms whether input changes query behavior, such as a syntax-safe value variation or a logged debug path in the lab. Do not fire a destructive payload just to prove that the site is live.
What this says about CMS security assumptions
CMS platforms get risky when abstraction layers hide too much. Developers trust the query builder. Operators trust the CMS release train. Attackers only need one place where the abstraction leaked.
This is why I like to test CMS security from the database backward. If the query emitted by the framework is wrong, the front-end route is not the real bug. The backend trust boundary is.
Conclusion
CVE-2026-9082 is a reminder that anonymous access plus database translation bugs is a bad combination, especially on PostgreSQL-backed Drupal sites. Patch core, verify the deployed version, tighten DB privileges, and use logs to confirm whether anyone has already started probing.
If you run Drupal in production, treat this as an exposure review, not just an update ticket.


