CVE-2026-77768: OpenPanel report.get Returns Any Report by Identifier Without Checking Project Access
The report.get procedure in packages/trpc/src/routers/report.ts accepted only a reportId and returned getReportById(reportId) directly. The enforceAccess middleware in packages/trpc/src/trpc.ts evaluates membership only when the input carries a projectId or organizationId key, so an input consisting of a reportId alone passed through unchecked, and getReportById in packages/db/src/services/reports.service.ts performs a findUnique on the report id with no project scoping. Any authenticated user could therefore read the full configuration of any saved report on the instance, including the owning projectId, event series, filters, breakdowns and formulas, by supplying its identifier. The adjacent update, delete and duplicate procedures resolve the report first and check getProjectAccess against the report's own projectId, so the omission was specific to this procedure.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Configuration
Update the report.get procedure so it does not call getReportById(reportId) without project scoping; instead resolve the report first and check getProjectAccess against the report's own projectId before returning the report.
OpenPanel trpc router: packages/trpc/src/routers/report.ts (report.get) getProjectAccess enforcement = Require project scoping for report.get using the report's own projectId (reject/deny when getProjectAccess fails) - Configuration
Modify enforceAccess so that when a request only carries reportId (no projectId or organizationId keys), access is still enforced (e.g., by deriving the report's projectId and evaluating membership accordingly) rather than passing the input through unchecked.
packages/trpc/src/trpc.ts (enforceAccess middleware) enforceAccess membership evaluation keys = Evaluate membership when resolving report access even if input contains only reportId - Configuration
Change getReportById in packages/db/src/services/reports.service.ts to scope the lookup by report id AND the authorized projectId/organizationId; avoid findUnique on report id without project scoping.
packages/db/src/services/reports.service.ts (getReportById) Project scoping in findUnique = Add project scoping to the findUnique query instead of querying by report id alone
Event History
Frequently Asked Questions
Who can exploit this issue?
Any authenticated user on the same OpenPanel instance can exploit it. The user does not need membership in the project that owns the targeted report.
What does an attacker need to retrieve another project's report?
They need only the report identifier and access to the report.get procedure. No user interaction or elevated privileges are required.
What information could be exposed?
The procedure can return the full saved-report configuration, including its owning projectId, event series, filters, breakdowns, and formulas. The issue is limited to reading reports; the described update, delete, and duplicate procedures perform project-access checks.
How can we determine whether this access-control gap exists in our deployment?
Review the report.get implementation and verify whether it accepts only reportId and directly calls getReportById(reportId) without resolving the report and checking access to its project. Also verify whether access middleware relies on projectId or organizationId being present in the request input.