GHSA-23rh-xw42-fq82: SQL Injection

Published Sep 10, 2026
·
Updated

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 reportsconfig 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, LOADFILE(), 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

1. Restrict reportsconfig permission to only highly trusted administrators 2. Deploy a WAF rule to block requests to /admin/bundle/customreports/custom-report/update containing SQL keywords in the configuration parameter 3. 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 reportsconfig permission + valid admin session) [Controller] CustomReportController::updateAction() ↓ $configuration = decodeJson($request->request->getString('configuration')) [Config Store] Configuration saved to customreports 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] pregmatch('/(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) ↓ jsondecode() → stdClass [Store] Persistent in database (customreports 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

1. Authenticate as an admin user with reportsconfig permission 2. Send a report update request with malicious SQL in the configuration:

Request

http POST /admin/bundle/customreports/custom-report/update HTTP/1.1 Host: <target-host> Content-Type: application/x-www-form-urlencoded Cookie: PHPSESSID=<validadminsession>

name=maliciousreport&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

3. Access the report data endpoint to retrieve extracted user credentials 4. Alternatively, the where field can be set to: 1=1 UNION SELECT TABLENAME, TABLESCHEMA, 1 FROM INFORMATIONSCHEMA.TABLES to enumerate all database tables

Expected Result

The custom report returns rows from arbitrary tables beyond what was intended, proving successful SQL injection.

Affected Component

- File: bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php - Method: buildQueryString() (lines 84-135), getBaseQuery() (lines 137-216), getData() (lines 25-58) - Class: Pimcore\Bundle\CustomReportsBundle\Tool\Adapter\Sql

Fix Recommendation

Replace the custom SQL concatenation approach with a parameterized query builder:

php // Instead of: $sql .= "\n" . $config['sql']; $sql .= "\n" . $config['from']; $sql .= "\n" . 'WHERE (' . $config['where'] . ')';

// Use a whitelist-based approach: // 1. Only allow predefined table names from a whitelist // 2. Use Doctrine QueryBuilder for WHERE conditions // 3. Use parameterized queries for all user-supplied values // 4. Cast LIMIT/OFFSET to integers

$sql .= ' LIMIT ' . (int)$offset . ',' . (int)$limit;

Resources

- CWE-89: SQL Injection - OWASP SQL Injection Prevention Cheat Sheet

Affected Software

3 affected componentsFixes available
composer/pimcore/pimcore<11.5.18
11.5.19
composer/pimcore/pimcore>=12.0.0-RC1<=12.3.9
12.3.10
composer/pimcore/pimcore>=2026.1.0<=2026.1.5
2026.1.6

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade composer/pimcore/pimcore to a version that resolves this vulnerability.

    Fixed in 11.5.19
  2. Upgrade

    Upgrade composer/pimcore/pimcore to a version that resolves this vulnerability.

    Fixed in 12.3.10
  3. Upgrade

    Upgrade composer/pimcore/pimcore to a version that resolves this vulnerability.

    Fixed in 2026.1.6
  4. Upgrade

    Upgrade Pimcore CustomReportsBundle (pimcore/bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php) to a version that resolves this vulnerability.

    Fixed in 2026.1.6
  5. Upgrade

    Upgrade Pimcore CustomReportsBundle (pimcore/bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php) to a version that resolves this vulnerability.

    Fixed in 12.3.10
  6. Upgrade

    Upgrade Pimcore CustomReportsBundle (pimcore/bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php) to a version that resolves this vulnerability.

    Fixed in 11.5.19
  7. Configuration

    Replace the custom SQL concatenation approach in Pimcore\Bundle\CustomReportsBundle\Tool\Adapter\Sql::{buildQueryString(), getBaseQuery()} with a parameterized query builder approach (use Doctrine QueryBuilder for WHERE conditions and parameterized queries for all user-supplied values from the report configuration fields: sql/from/where/groupby).

    CustomReportsBundle Sql adapter (Pimcore\Bundle\CustomReportsBundle\Tool\Adapter\Sql) buildQueryString/getBaseQuery parameterization = parameterized queries (Doctrine QueryBuilder)
  8. Configuration

    Ensure LIMIT/OFFSET values used in Sql::getBaseQuery()/buildQueryString are cast to integers (secondary injection point at the LIMIT clause where $offset and $limit are interpolated).

    CustomReportsBundle Sql adapter (Pimcore\Bundle\CustomReportsBundle\Tool\Adapter\Sql) LIMIT/OFFSET handling = cast (int) for both $limit and $offset

Event History

Sep 10, 2026
Advisory Published
via GitHub·07:25 PM
Data Sourced
via GitHub·07:25 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who can exploit this issue?

An attacker must be authenticated and have the reports_config permission. Restricting that permission to highly trusted administrators reduces the exposed user population.

2

What access could exploitation provide?

An attacker can inject SQL through report configuration fields and may read, modify, or delete all database data. The advisory describes this as complete data compromise.

3

Which releases include patches?

The listed patched versions are 2026.1.6, 12.3.10, and 11.5.19.

4

What should be done if patching cannot happen immediately?

Restrict reports_config permission to only highly trusted administrators. The advisory also recommends deploying a WAF rule, but the provided information does not specify the rule details.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203