CVE-2026-55416
Pimcore: SQL Injection in Mautic Custom Reports Bundle Due to Direct Concatenation of User-Controlled Configuration Fields Without Parameterization
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, an authenticated user with reports_config permission can place attacker-controlled SQL fragments in the sql, from, where, and groupby fields of a Custom Reports configuration processed by bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php. The buildQueryString() method concatenates these values into a database query, while a blacklist omits dangerous constructs such as additional data-manipulation statements, comments, subqueries, and multiple statements. The getData() method also previously interpolated offset and limit values into a LIMIT clause without integer casting. Executing the configured report reaches fetchAllAssociative() with the constructed query and can disclose, modify, or delete arbitrary database data. This issue is fixed in versions 11.5.19, 12.3.10, and 2026.1.6.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.8
Pimcore: SQL Injection in Mautic Custom Reports Bundle Due to Direct Concatenation of User-Controlled Configuration Fields Without Parameterization
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, an authenticated user with reports_config permission can place attacker-controlled SQL fragments in the sql, from, where, and groupby fields of a Custom Reports configuration processed by bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php. The buildQueryString() method concatenates these values into a database query, while a blacklist omits dangerous constructs such as additional data-manipulation statements, comments, subqueries, and multiple statements. The getData() method also previously interpolated offset and limit values into a LIMIT clause without integer casting. Executing the configured report reaches fetchAllAssociative() with the constructed query and can disclose, modify, or delete arbitrary database data. This issue is fixed in versions 11.5.19, 12.3.10, and 2026.1.6.
- Record
CVE-2026-55416- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-89
- Updated
- 2026-11-02
EUVDEUVD-2026-77636
8.8
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, an authenticated user with reports_config permission can place attacker-controlled SQL fragments in the sql, from, where, and groupby fields of a Custom Reports configuration processed by bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php. The buildQueryString() method concatenates these values into a database query, while a blacklist omits dangerous constructs such as additional data-manipulation statements, comments, subqueries, and multiple statements. The getData() method also previously interpolated offset and limit values into a LIMIT clause without integer casting. Executing the configured report reaches fetchAllAssociative() with the constructed query and can disclose, modify, or delete arbitrary database data. This issue is fixed in versions 11.5.19, 12.3.10, and 2026.1.6.
- Record
EUVD-2026-77636- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-23rh-xw42-fq82
8.8
Pimcore: SQL Injection in Custom Reports via Malicious Report Configuration
Security Advisory: SQL Injection in Custom Reports via Malicious Report Configuration
Summary
Impact
A SQL injection vulnerability exists in the Custom Reports bundle (bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php:84-135). An authenticated attacker with reports_config permission can inject arbitrary SQL via the report configuration fields (sql, from, where, groupby), which are directly concatenated into SQL queries without parameterization. The only protection is a regex blacklist that checks for ALTER|CREATE|DROP|RENAME|TRUNCATE|UPDATE|DELETE keywords, which is trivially bypassable — it does not block INSERT, UNION SELECT, LOAD_FILE(), INTO OUTFILE, stacked queries, subqueries, or MySQL comment injection (/*!*/). Exploitation allows reading, modifying, or deleting all data in the database, leading to complete data compromise.
Additionally, the LIMIT clause at line 51 directly interpolates $offset and $limit without integer casting, creating a secondary injection point.
Patches
Versions 2026.1.6, 12.3.10, 11.5.19.
Workarounds
- Restrict
reports_configpermission to only highly trusted administrators - Deploy a WAF rule to block requests to
/admin/bundle/customreports/custom-report/updatecontaining SQL keywords in theconfigurationparameter - Replace the custom SQL adapter with a parameterized query builder approach
Attack Path (Validation Evidence)
[Entry Point] POST /admin/bundle/customreports/custom-report/update HTTP/1.1
↓ (requires reports_config permission + valid admin session)
[Controller] CustomReportController::updateAction()
↓ $configuration = decodeJson($request->request->getString('configuration'))
[Config Store] Configuration saved to custom_reports database table
[Config Load] Tool\Config::getByName() loads stdClass $config from DB
↓
[Adapter] Sql::getBaseQuery() → Sql::buildQueryString($config)
↓ Directly concatenates config fields:
[Vulnerable] $sql .= "\n" . $config['sql']; // Line 92
$sql .= "\n" . $config['from']; // Line 103
$sql .= "\n" . 'WHERE (' . $config['where'] . ')'; // Line 110
$sql .= "\n" . $config['groupby']; // Line 117
[Weak Guard] preg_match('/(ALTER|CREATE|DROP|RENAME|TRUNCATE|UPDATE|DELETE)\s/i', ...)
↓ ✗ Bypassable — missing INSERT, UNION, SELECT, subqueries, comments
[Execution] $db->fetchAllAssociative($sql); // Line 54
↓
[Impact] Arbitrary SQL execution — full database compromise
Taint Flow (Validation Evidence)
Source: $request->request->getString('configuration') (HTTP POST body, user-controlled)
↓ json_decode() → stdClass
[Store] Persistent in database (custom_reports table)
[Load] Config::getByName() → stdClass $config
↓ ✗ No sanitization (only bypassable regex blacklist)
[Sink] $db->fetchAllAssociative($concatenatedSql)
↓
Impact: Attacker-controlled SQL executed against the database
Proof of Concept
Steps
- Authenticate as an admin user with
reports_configpermission - Send a report update request with malicious SQL in the configuration:
Request
POST /admin/bundle/customreports/custom-report/update HTTP/1.1
Host: <target-host>
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=<valid_admin_session>
name=malicious_report&configuration=%7B%22sql%22%3A%22SELECT%20id%2C%20username%2C%20password%20FROM%20users%22%2C%22from%22%3A%22users%22%2C%22where%22%3A%221%3D1%22%2C%22groupby%22%3A%22%22%2C%22dataSourceConfig%22%3A%7B%7D%7D
- Access the report data endpoint to retrieve extracted user credentials
- Alternatively, the
wherefield can be set to:
to enumerate all database tables1=1 UNION SELECT TABLE_NAME, TABLE_SCHEMA, 1 FROM INFORMATION_SCHEMA.TABLES
Expected Result
The custom report returns rows from arbitrary tables beyond what was intended, proving successful SQL…
- Record
GHSA-23rh-xw42-fq82- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-89
- Updated
- 2026-11-02
NVD
8.8
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, an authenticated user with reports_config permission can place attacker-controlled SQL fragments in the sql, from, where, and groupby fields of a Custom Reports configuration processed by bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php. The buildQueryString() method concatenates these values into a database query, while a blacklist omits dangerous constructs such as additional data-manipulation statements, comments, subqueries, and multiple statements. The getData() method also previously interpolated offset and limit values into a LIMIT clause without integer casting. Executing the configured report reaches fetchAllAssociative() with the constructed query and can disclose, modify, or delete arbitrary database data. This issue is fixed in versions 11.5.19, 12.3.10, and 2026.1.6.
- Record
CVE-2026-55416- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-89
- Updated
- 2026-11-02
OSV
8.8
Pimcore: SQL Injection in Mautic Custom Reports Bundle Due to Direct Concatenation of User-Controlled Configuration Fields Without Parameterization
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, an authenticated user with reports_config permission can place attacker-controlled SQL fragments in the sql, from, where, and groupby fields of a Custom Reports configuration processed by bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php. The buildQueryString() method concatenates these values into a database query, while a blacklist omits dangerous constructs such as additional data-manipulation statements, comments, subqueries, and multiple statements. The getData() method also previously interpolated offset and limit values into a LIMIT clause without integer casting. Executing the configured report reaches fetchAllAssociative() with the constructed query and can disclose, modify, or delete arbitrary database data. This issue is fixed in versions 11.5.19, 12.3.10, and 2026.1.6.
- Record
CVE-2026-55416- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-89
- Updated
- 2026-11-02
OSVGHSA-23rh-xw42-fq82
8.8
Pimcore: SQL Injection in Custom Reports via Malicious Report Configuration
Security Advisory: SQL Injection in Custom Reports via Malicious Report Configuration
Summary
Impact
A SQL injection vulnerability exists in the Custom Reports bundle (bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php:84-135). An authenticated attacker with reports_config permission can inject arbitrary SQL via the report configuration fields (sql, from, where, groupby), which are directly concatenated into SQL queries without parameterization. The only protection is a regex blacklist that checks for ALTER|CREATE|DROP|RENAME|TRUNCATE|UPDATE|DELETE keywords, which is trivially bypassable — it does not block INSERT, UNION SELECT, LOAD_FILE(), INTO OUTFILE, stacked queries, subqueries, or MySQL comment injection (/*!*/). Exploitation allows reading, modifying, or deleting all data in the database, leading to complete data compromise.
Additionally, the LIMIT clause at line 51 directly interpolates $offset and $limit without integer casting, creating a secondary injection point.
Patches
Versions 2026.1.6, 12.3.10, 11.5.19.
Workarounds
- Restrict
reports_configpermission to only highly trusted administrators - Deploy a WAF rule to block requests to
/admin/bundle/customreports/custom-report/updatecontaining SQL keywords in theconfigurationparameter - Replace the custom SQL adapter with a parameterized query builder approach
Attack Path (Validation Evidence)
[Entry Point] POST /admin/bundle/customreports/custom-report/update HTTP/1.1
↓ (requires reports_config permission + valid admin session)
[Controller] CustomReportController::updateAction()
↓ $configuration = decodeJson($request->request->getString('configuration'))
[Config Store] Configuration saved to custom_reports database table
[Config Load] Tool\Config::getByName() loads stdClass $config from DB
↓
[Adapter] Sql::getBaseQuery() → Sql::buildQueryString($config)
↓ Directly concatenates config fields:
[Vulnerable] $sql .= "\n" . $config['sql']; // Line 92
$sql .= "\n" . $config['from']; // Line 103
$sql .= "\n" . 'WHERE (' . $config['where'] . ')'; // Line 110
$sql .= "\n" . $config['groupby']; // Line 117
[Weak Guard] preg_match('/(ALTER|CREATE|DROP|RENAME|TRUNCATE|UPDATE|DELETE)\s/i', ...)
↓ ✗ Bypassable — missing INSERT, UNION, SELECT, subqueries, comments
[Execution] $db->fetchAllAssociative($sql); // Line 54
↓
[Impact] Arbitrary SQL execution — full database compromise
Taint Flow (Validation Evidence)
Source: $request->request->getString('configuration') (HTTP POST body, user-controlled)
↓ json_decode() → stdClass
[Store] Persistent in database (custom_reports table)
[Load] Config::getByName() → stdClass $config
↓ ✗ No sanitization (only bypassable regex blacklist)
[Sink] $db->fetchAllAssociative($concatenatedSql)
↓
Impact: Attacker-controlled SQL executed against the database
Proof of Concept
Steps
- Authenticate as an admin user with
reports_configpermission - Send a report update request with malicious SQL in the configuration:
Request
POST /admin/bundle/customreports/custom-report/update HTTP/1.1
Host: <target-host>
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=<valid_admin_session>
name=malicious_report&configuration=%7B%22sql%22%3A%22SELECT%20id%2C%20username%2C%20password%20FROM%20users%22%2C%22from%22%3A%22users%22%2C%22where%22%3A%221%3D1%22%2C%22groupby%22%3A%22%22%2C%22dataSourceConfig%22%3A%7B%7D%7D
- Access the report data endpoint to retrieve extracted user credentials
- Alternatively, the
wherefield can be set to:
to enumerate all database tables1=1 UNION SELECT TABLE_NAME, TABLE_SCHEMA, 1 FROM INFORMATION_SCHEMA.TABLES
Expected Result
The custom report returns rows from arbitrary tables beyond what was intended, proving successful SQL…
- Record
GHSA-23rh-xw42-fq82- CVSS 3.1
- 8.8 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - Weakness
- CWE-89
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
pimcore/pimcorePackagist |
2026.1.0 to 2026.1.5 | 2026.1.6 |
pimcore/pimcorePackagist |
12.0.0-RC1 to 12.3.9 | 12.3.10 |
pimcore/pimcorePackagist |
before 11.5.18 | 11.5.18 |
pimcore/pimcorePackagist |
2026.1.0 up to 2026.1.6, plus listed versions v2026.1.0v2026.1.1v2026.1.2v2026.1.3v2026.1.4v2026.1.5 |
2026.1.6 |
pimcore/pimcorePackagist |
12.0.0-RC1 up to 12.3.10, plus listed versions v12.0.0v12.0.0-RC1v12.0.0-RC2v12.0.1v12.0.2 Show 24 moreShow lessv12.0.3v12.0.4v12.1.0v12.1.1v12.1.2v12.1.3v12.1.4v12.1.5v12.2.0v12.2.1v12.2.2v12.2.3v12.2.4v12.3.0v12.3.1v12.3.1.1v12.3.2v12.3.3v12.3.4v12.3.5v12.3.6v12.3.7v12.3.8v12.3.9 |
12.3.10 |
pimcore/pimcorePackagist |
before 11.5.19, plus listed versions 10.0.82.2.02.2.12.2.22.3.0 Show 45 moreShow less3.0.03.0.13.0.23.0.33.0.43.0.53.0.63.1.03.1.14.0.04.0.14.1.04.1.14.1.24.1.34.2.04.3.04.3.14.4.04.4.14.4.24.4.34.5.04.6.04.6.14.6.24.6.34.6.44.6.5v10.0.0v10.0.0-BETA1v10.0.0-BETA2v10.0.0-BETA3v10.0.0-BETA4v10.0.1v10.0.2v10.0.3v10.0.4v10.0.5v10.0.6v10.0.7v10.0.9v10.1.0v10.1.1v10.1.2 |
11.5.19 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-55416 is a high vulnerability (CVSS 8.8) in Pimcore, published September 10, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.65%, the 51st percentile. Fixed in pimcore/pimcore 2026.1.6.
References
github.com/pimcore/pimcore/security/advisories/GHSA-23rh-xw42-fq82
github.com/pimcore/pimcore/pull/19175
github.com/pimcore/pimcore/commit/1999fee27ed0d027ad5b8195ecf6e27243729530
github.com/pimcore/pimcore/releases/tag/v12.3.10
github.com/pimcore/pimcore/releases/tag/v2026.1.6
github.com/pimcore/pimcore/releases/tag/v11.5.19
Left out here: 246 versions and the rest of 2 source descriptions. The JSON record has them.