{"id":"GHSA-6wcc-39rp-hh9p","summary":"@hypequery/clickhouse has SQL Injection in parameter escaping that allows arbitrary SQL execution","details":"A SQL injection vulnerability exists in the `escapeValue()` function used for parameter substitution. `escapeValue()` dispatches on the type of the parameter value, and two of its branches failed to escape safely. An attacker who can control a parameter value can terminate the enclosing string literal and have the rest of the value parsed as SQL.\n\n**Vector 1 - string parameters. Fixed in 2.0.2.** The string branch escaped `'` as `''` but left `\\\\` untouched. ClickHouse honours C-style backslash escapes as well as SQL-standard quote doubling, so a value ending in an odd number of backslashes escapes the closing quote and the next parameter lands outside the literal:\n\n```\nwhere('a', 'eq', 'x\\\\')          -\u003e   WHERE a = 'x\\\\' AND b = ' OR 1=1 --'\n```\n\n**Vector 2 - object and array parameters. Fixed in 2.5.1, NOT in 2.0.2.** The final branch of the same function rendered non-scalar values as `` `'${JSON.stringify(value)}'` `` with no escaping at all. JSON has no reason to escape the apostrophe, so any nested string containing `'` terminates the literal:\n\n```\nwhere('meta', 'eq', { k: \\\"x' OR 1=1 -- \\\" })\n                                -\u003e   WHERE meta = '{\\\"k\\\":\\\"x' OR 1=1 -- \\\"}'\n```\n\nThe 2.0.2 patch changed only the string branch and did not address this. Vector 2 remained exploitable in **2.0.2, 2.1.0, 2.1.1, 2.1.2, 2.1.3, 2.2.0, 2.3.0, 2.4.0 and 2.5.0** - every release this advisory previously reported as patched.\n\n**Who is impacted.** Any application on a version below 2.5.1 that passes user-controlled input as a query parameter. Both vectors are reachable through the documented public API: `.where(column, operator, value)`, the `in` operator, and `adapter.render()` / `rawQuery()`.\n\n**Schema type declarations do not mitigate vector 2.** `createQueryBuilder().table()` builds its state with an empty column map, so the filter validator has no declared type to check against and returns without validating. Even where a schema is supplied, only `String`, `Int32`, `Int64`, `Float64` and `Date` columns are type-checked - `Map`, `Array`, `Bool`, `UUID`, `DateTime`, `UInt*`, `Enum` and `Nullable` columns are not - and any column name containing a `.` skips validation entirely.\n\n## Patches\n\nUpgrade to **2.5.1 or later**. Both vectors are closed there.\n\n- **Vector 1** - fixed in **2.0.2** by `2dc1df7bae` (the referenced `4dfa9d77` is the same change\n  on the pull-request branch). Escapes backslashes before escaping single quotes.\n- **Vector 2** - fixed in **2.5.1** by `2879161a81`, which routes the serialised JSON back through  `escapeValue()` so nested quotes are doubled. The same commit also rejects non-finite numbers and  invalid `Date` values instead of emitting them into the query.\n\nFor anyone auditing the history: the vector-2 fix is bundled inside `2879161a81`, whose commit message is *\\\"parenthesize logical groups in WHERE to preserve AND/OR precedence (#349)\\\"*. Commit `4a1d4e38aa` (#350), whose message *does* describe the escaping fix, changes only a `bigint` branch - the escaping fix is already present in its parent.\n\n## Workarounds\n\nUpgrading is the only complete fix.\n\nFor **vector 2** only, applications on 2.0.2–2.5.0 that cannot upgrade can serialise non-scalar parameters themselves and pass the resulting string. That routes the value through the string branch, which is correctly escaped from 2.0.2 onward:\n\n```js\n.where('meta', 'eq', JSON.stringify(value))   // safe on \u003e= 2.0.2\n```\n\nThere is no workaround for **vector 1** other than upgrading to 2.0.2 or later.\n\nDo not substitute application-level input validation or sanitisation for either fix. Correct escaping depends on the literal context the library constructs, so the library has to own it.","aliases":["CVE-2026-54658"],"modified":"2026-08-04T20:45:18.872507897Z","published":"2026-07-28T22:19:23Z","database_specific":{"nvd_published_at":"2026-07-28T23:17:08Z","cwe_ids":["CWE-89"],"severity":"CRITICAL","github_reviewed":true,"github_reviewed_at":"2026-07-28T22:19:23Z"},"references":[{"type":"WEB","url":"https://github.com/hypequery/hypequery/security/advisories/GHSA-6wcc-39rp-hh9p"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-54658"},{"type":"WEB","url":"https://github.com/hypequery/hypequery/pull/349"},{"type":"WEB","url":"https://github.com/hypequery/hypequery/commit/2879161a810fed2c2222f785816ff05510976960"},{"type":"WEB","url":"https://github.com/hypequery/hypequery/commit/2dc1df7bae"},{"type":"WEB","url":"https://github.com/hypequery/hypequery/commit/4dfa9d77d70a08b970e722268b75ca7d13db0bdf"},{"type":"PACKAGE","url":"https://github.com/hypequery/hypequery"},{"type":"WEB","url":"https://github.com/hypequery/hypequery/blob/main/packages/clickhouse/CHANGELOG.md#202"},{"type":"WEB","url":"https://github.com/hypequery/hypequery/releases/tag/@hypequery/clickhouse@2.0.2"},{"type":"WEB","url":"https://github.com/hypequery/hypequery/releases/tag/@hypequery/clickhouse@2.5.1"}],"affected":[{"package":{"name":"@hypequery/clickhouse","ecosystem":"npm","purl":"pkg:npm/%40hypequery/clickhouse"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.5.1"}]}],"database_specific":{"last_known_affected_version_range":"\u003c 2.0.2","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-6wcc-39rp-hh9p/GHSA-6wcc-39rp-hh9p.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"}]}