From eb304b80c9cb997634509df8ef8155fe8ef619dd Mon Sep 17 00:00:00 2001 From: chappie-daemon Date: Sun, 1 Nov 2026 09:47:35 -0500 Subject: [PATCH] fix(deps): bump knex to 3.2.9 for the search_path SQL injection AIKIDO-2026-10469: knex 0.0.1-3.2.8 interpolates values passed to searchPath for the Postgres dialect into generated SQL without validating or escaping them. nostream declares knex 2.4.2, so the image ships a vulnerable copy. 3.2.9 is the smallest published version that contains the fix (#6411 escapes double quotes in searchPath), and it is the version Aikido names. 3.2.10 and 3.3.0 carry no further security fix; 3.3.0 also lands a fix to something other than this advisory, so the smallest bump above the fixed version is the one that changes the least. The repo never sets searchPath: grep -rn "search_path" src/ finds no match, so the vulnerable code path is not reachable here. The bump is still taken, because the vulnerable dependency should not ship. knex 3.0.0 drops Node < 16 (the repo requires >=24.14.1) and 3.2.0 tightens the RawBinding type. That surfaced one compile error: benchmark-queries.ts passed "bindings as readonly unknown[]" to db.raw(), and an assertion to unknown no longer satisfies RawBinding. Dropping the assertion is the fix, not a new one - toSQL().bindings is already the accepted type, and the emitted JavaScript is byte-identical with and without the assertion. --- .changeset/knex-3-2-9-security.md | 22 +++++++++++++++++++++ package.json | 2 +- pnpm-lock.yaml | 32 +++++++++++++++---------------- src/scripts/benchmark-queries.ts | 2 +- 4 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 .changeset/knex-3-2-9-security.md diff --git a/.changeset/knex-3-2-9-security.md b/.changeset/knex-3-2-9-security.md new file mode 100644 index 000000000..9ee413642 --- /dev/null +++ b/.changeset/knex-3-2-9-security.md @@ -0,0 +1,22 @@ +--- +"nostream": patch +--- + +fix(deps): bump knex to 3.2.9 for the search_path SQL injection (AIKIDO-2026-10469) + +knex 0.0.1–3.2.8 interpolates values passed to `searchPath` for the Postgres +dialect into generated SQL without validating or escaping them, so a value an +attacker can influence becomes an injected identifier. 3.2.9 escapes the double +quotes (#6411); this repository declares `knex` 2.4.2 on both the default branch +and `rewrite/main`. + +nostream never sets `searchPath` — `grep -rn "search_path" src/` finds nothing — +so the reachable path is not exercised today, and the bump is taken to remove a +vulnerable dependency from the image, not to close a reachable hole. + +knex 3.0.0 drops Node < 16, which the repo already requires (>=24.14.1), and 3.2.0 +tightens `RawBinding`. The one compile error that surfaced, +`src/scripts/benchmark-queries.ts` passing `bindings as readonly unknown[]` to +`db.raw()`, is fixed by dropping the assertion: `toSQL().bindings` is already the +accepted type. The emitted JavaScript is byte-identical with and without the +assertion. diff --git a/package.json b/package.json index dfbfc5b21..3afe66fa3 100644 --- a/package.json +++ b/package.json @@ -180,7 +180,7 @@ "colorette": "^2.0.20", "express": "4.22.1", "js-yaml": "4.3.2", - "knex": "2.4.2", + "knex": "3.2.9", "ora": "^9.3.0", "pg": "8.9.0", "pg-query-stream": "4.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c5adf70b0..631c386dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,8 +53,8 @@ importers: specifier: 4.3.2 version: 4.3.2 knex: - specifier: 2.4.2 - version: 2.4.2(pg@8.9.0) + specifier: 3.2.9 + version: 3.2.9(pg-query-stream@4.3.0(pg@8.9.0))(pg@8.9.0) ora: specifier: ^9.3.0 version: 9.4.0 @@ -2530,10 +2530,6 @@ packages: resolution: {integrity: sha512-i0/MaqBtdbnJ4XQs4Pmyb+oFQl+q0lsAmokVUH92SlSw4fkeAcG3bVon+Qt7hmtF+u3Het6o4VgrcY3qAoEB6w==} engines: {node: ^12.20.0 || >=14} - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} @@ -3592,9 +3588,9 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - knex@2.4.2: - resolution: {integrity: sha512-tMI1M7a+xwHhPxjbl/H9K1kHX+VncEYcvCx5K00M16bWvpYPKAZd6QrCu68PtHAdIZNQPWZn0GVhqVBEthGWCg==} - engines: {node: '>=12'} + knex@3.2.9: + resolution: {integrity: sha512-dtAILTjBMaG8YloP5oBxohDIKyIsdQ/TkcVvSjhsksvsjeH63Y0PADyuMDfNZKbVT3Rlx3vEYVBlecbPT/KerA==} + engines: {node: '>=16'} hasBin: true peerDependencies: better-sqlite3: '*' @@ -3602,6 +3598,7 @@ packages: mysql2: '*' pg: '*' pg-native: '*' + pg-query-stream: ^4.14.0 sqlite3: '*' tedious: '*' peerDependenciesMeta: @@ -3615,6 +3612,8 @@ packages: optional: true pg-native: optional: true + pg-query-stream: + optional: true sqlite3: optional: true tedious: @@ -4348,8 +4347,8 @@ packages: pg-connection-string@2.12.0: resolution: {integrity: sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==} - pg-connection-string@2.5.0: - resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==} + pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} pg-cursor@2.19.0: resolution: {integrity: sha512-J5cF1MUz7LRJ9emOqF/06QjabMHMZy587rSPF0UuA8rCwKeeYl2co8Pp+6k5UU9YrAYHMzWkLxilfZB0hqsWWw==} @@ -8131,8 +8130,6 @@ snapshots: commander@9.1.0: {} - commander@9.5.0: {} - common-ancestor-path@1.0.1: {} commondir@1.0.1: {} @@ -9231,10 +9228,10 @@ snapshots: kleur@4.1.5: {} - knex@2.4.2(pg@8.9.0): + knex@3.2.9(pg-query-stream@4.3.0(pg@8.9.0))(pg@8.9.0): dependencies: colorette: 2.0.19 - commander: 9.5.0 + commander: 10.0.1 debug: 4.3.4 escalade: 3.2.0 esm: 3.2.25 @@ -9242,13 +9239,14 @@ snapshots: getopts: 2.3.0 interpret: 2.2.0 lodash: 4.18.1 - pg-connection-string: 2.5.0 + pg-connection-string: 2.6.2 rechoir: 0.8.0 resolve-from: 5.0.0 tarn: 3.0.2 tildify: 2.0.0 optionalDependencies: pg: 8.9.0 + pg-query-stream: 4.3.0(pg@8.9.0) transitivePeerDependencies: - supports-color @@ -10219,7 +10217,7 @@ snapshots: pg-connection-string@2.12.0: {} - pg-connection-string@2.5.0: {} + pg-connection-string@2.6.2: {} pg-cursor@2.19.0(pg@8.9.0): dependencies: diff --git a/src/scripts/benchmark-queries.ts b/src/scripts/benchmark-queries.ts index ac76a91e7..8fe5d5c46 100644 --- a/src/scripts/benchmark-queries.ts +++ b/src/scripts/benchmark-queries.ts @@ -157,7 +157,7 @@ async function explain(db: Knex, query: Knex.QueryBuilder | Knex.Raw): Promise( `EXPLAIN (ANALYZE, BUFFERS, VERBOSE, FORMAT JSON) ${sql}`, - bindings as readonly unknown[], + bindings, ) return rows[0]['QUERY PLAN'][0] }