Pimcore SQLi: When a 'Fix' is Just a Band-Aid
Jan 15, 2026·6 min read
Executive Summary (TL;DR)
Pimcore tried to fix an SQL injection in 2023 by deleting double dashes (`--`) and hiding error messages. It didn't work. CVE-2026-23492 is the result: a high-severity Blind SQL Injection in the Admin Search Find API that allows attackers to exfiltrate the entire database using time-based payloads. If you run Pimcore < 11.5.14 or < 12.3.1, patch immediately.
A critical Blind SQL Injection vulnerability in Pimcore's Admin Search API caused by a failed attempt to patch a previous vulnerability (CVE-2023-30848). Developers relied on a blacklist approach—stripping SQL comments—and error suppression, leaving the core injection flaw wide open to authenticated attackers.
The Hook: Searching for Trouble
Every complex web application needs a search bar, and in the world of Content Management Systems (CMS), the Admin Search is the nerve center. It allows administrators to query users, assets, objects, and documents. In Pimcore, this functionality is handled by the Admin Search Find API at /admin/search/search/find. It’s a powerful endpoint designed to take complex filters and return precise data.
However, power often breeds fragility. When you allow users to define how the database is queried—specifying fields, filters, and structures—you are walking a tightrope over the pit of SQL injection. The developers knew this. They had already been bitten by this exact endpoint in the past (CVE-2023-30848). But as we'll see, recognizing a problem and actually fixing it are two very different disciplines.
This vulnerability isn't just a coding error; it's a lesson in why "mitigation" is not a synonym for "remediation." The feature meant to help admins find content is now the perfect tool for attackers to find your secrets.
The Flaw: A History of Bad Ideas
To understand CVE-2026-23492, we have to look at the ghost of vulnerabilities past. In CVE-2023-30848, attackers found they could inject SQL via the fields[] parameter. The development team's response was... optimistic. They implemented two specific defenses: a blacklist sanitizer and error suppression.
First, they added str_replace('--', '', $fields). This logic assumes that if you remove the SQL comment syntax (--), an attacker can't construct a valid malicious query. This is akin to removing the firing pin from a gun but leaving the loaded chamber and hammer intact. SQL injection does not require comments; they are just a convenience for attackers to ignore the rest of the original query.
Second, they wrapped the execution in a try/catch block that suppressed SyntaxErrorException. This stopped the application from vomiting stack traces (which prevents Error-Based SQLi), but it did absolutely nothing to stop the database from executing a query that didn't cause a syntax error. If the query runs—even slowly—we have a vulnerability.
The Code: The Smoking Gun
Let's look at the PHP code responsible for this logic. This snippet from SearchController.php shows exactly how the incomplete patch was implemented. It essentially scrubs the input for one specific character sequence and then feeds it into the query builder.
// Pimcore\Bundle\AdminBundle\Controller\Searchadmin\SearchController.php
$fields = $allParams['fields'];
// The "Fix": remove sql comments (useless against advanced injection)
$fields = str_replace('--', '', $fields);
foreach ($fields as $f) {
// The input is split, but the first part is still raw user data
$parts = explode('~', $f);
// $parts[0] is eventually concatenated into the SQL query
// ...
}
try {
// The query executes. If it's valid SQL, it runs.
$hits = $searcherList->load();
} catch (SyntaxErrorException $syntaxErrorException) {
// Hiding the evidence doesn't stop the crime
throw new \InvalidArgumentException('Check your arguments.');
}The fundamental issue here is concatenation. The variable $parts[0] (derived from the GET parameter) is treated as a column name or expression in the generated SQL. Because the developers only stripped --, we can still inject spaces, quotes, logic operators (AND, OR), and functions (SLEEP, BENCHMARK).
The Exploit: Sleeping on the Job
Since the application suppresses errors, we can't use standard error-based techniques. We also can't easily see the output of our injection in the JSON response because the query logic is complex. This forces us into Blind SQL Injection territory.
The most reliable way to prove existence is a Time-Based attack. We ask the database a question: "Is the first letter of the database version '5'?" If the answer is YES, we tell the database to sleep for 5 seconds. If NO, it returns immediately.
Here is the attack flow:
The Payload:
We inject a logical test into the fields[] array. Note that we don't need -- to make this valid SQL if we carefully balance our parentheses.
GET /admin/search/search/find?query=2&
fields[]=field1 AND IF(1=1,SLEEP(5),0)~field2&
filter=[{"property":"value"}]&
class=classnameIf the server hangs for 5 seconds, we have confirmed RCE (Remote Code Execution) on the database context. An attacker would script this to extract the admin password hash character by character.
The Impact: Total Recall
Why should you panic? Because this is the Admin interface. While the vulnerability requires authentication, in many organizations, "Admin" access is tiered. A lower-privileged user with access to the search function (e.g., a content editor) could use this to elevate privileges to Super Admin by dumping the users table.
Furthermore, the database user backing a Pimcore instance often has significant privileges. An attacker could:
- Exfiltrate Customer Data: Dump the entire customer database via blind extraction.
- Read Files: If the DB user has
FILEprivileges, they could read/etc/passwdor configuration files. - Lateral Movement: Use the database access to pivot to other systems connected to the same DB cluster.
This isn't just about reading data; it's about owning the platform's foundation.
The Fix: Do It Right This Time
The remediation is straightforward but requires a shift in mindset. You cannot sanitize SQL injection with str_replace. You must use Parameterization or strictly allow-list the input.
Pimcore has released versions 11.5.14 and 12.3.1 to address this. The fix involves refactoring the Searcher class to validate that the input provided in fields corresponds to actual existing columns in the data definition, rejecting any input that contains SQL logic or unknown identifiers.
If you cannot patch immediately, you can attempt to block these requests at the WAF level, but be warned: WAF rules for SQLi are notoriously easy to bypass with obfuscation. The only real fix is the patch.
Official Patches
Fix Analysis (1)
Technical Appendix
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:HAffected Systems
Affected Versions Detail
| Product | Affected Versions | Fixed Version |
|---|---|---|
Pimcore Pimcore | < 11.5.14 | 11.5.14 |
Pimcore Pimcore | >= 12.0.0-RC1, < 12.3.1 | 12.3.1 |
| Attribute | Detail |
|---|---|
| CWE | CWE-89 (SQL Injection) |
| CVSS v3.1 | 8.8 (High) |
| Attack Vector | Network (Authenticated) |
| Vulnerability Type | Blind SQL Injection (Boolean/Time-based) |
| Previous Fail | Incomplete fix for CVE-2023-30848 |
| Status | Patched |
MITRE ATT&CK Mapping
The software constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component.
Known Exploits & Detection
Vulnerability Timeline
Subscribe to updates
Get the latest CVE analysis reports delivered to your inbox.