# @hypequery/clickhouse has SQL Injection in parameter escaping that allows arbitrary SQL execution

escapeValue() in @hypequery/clickhouse failed to escape backslashes and JSON-serialized objects, letting attacker-controlled parameters break out of string literals and inject arbitrary SQL.

- Payout: Research
- Severity: critical
- Program: @hypequery/clickhouse
- Found by: cobyge, BarakSrour
- Disclosed: 2026-07-28
- CVE: CVE-2026-54658
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-6wcc-39rp-hh9p
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-6wcc-39rp-hh9p
- Tags: area:oss domain:oss impact:data-leak kind:research platform:ghsa sev:critical tech:nodejs technique:incomplete-fix technique:source-review vuln:sqli

**Target:** npm library query builder / ClickHouse SQL parameter substitution
**Root cause:** escapeValue() escaped single quotes but not backslashes (ClickHouse honors C-style backslash escapes), and rendered object/array values via JSON.stringify inside a quoted literal with no escaping at all.
**Steps:**
1. Vector 1: pass a string parameter ending in an odd number of backslashes, e.g. `where('a', 'eq', 'x\\')`, producing `WHERE a = 'x\\' AND b = ' OR 1=1 --'`
2. Vector 2: pass an object whose nested string contains an apostrophe, e.g. `where('meta', 'eq', { k: "x' OR 1=1 -- " })`, producing `WHERE meta = '{"k":"x' OR 1=1 -- "}'`
3. Reach via documented API: `.where()`, `in` operator, `adapter.render()` / `rawQuery()`
**How found:** Auditing escapeValue()'s per-type dispatch branches; noticed the string branch left backslashes unescaped despite ClickHouse's C-style escape support, and the non-scalar branch used raw JSON.stringify inside a quoted literal.
**Exploitation:** Any app passing user-controlled input as a query parameter on versions <2.5.1 lets the attacker terminate the enclosing string literal and append arbitrary SQL (e.g. `OR 1=1 --`), altering query semantics and potentially exfiltrating data.
**Insight:** When a DB honors both backslash and quote-doubling escapes, escaping only quotes is insufficient; and any serializer (JSON.stringify) placed inside a SQL literal must itself be re-escaped. Also check that schema-based type validators actually cover Map/Array/Nullable and dotted column names, since gaps there leave injection reachable.

## Proof of concept (copied exactly from the original report)

**Backslash-terminated string parameter escapes quote**

```
where('a', 'eq', 'x\\')          ->   WHERE a = 'x\\' AND b = ' OR 1=1 --'
```

