Every CVE Search/ Get API key

CVE-2026-44635

Kysely: JSON-path traversal injection via unsanitized path-leg metacharacters in `JSONPathBuilder.key()` / `.at()`

7.5 HighFix available

Kysely is a type-safe TypeScript SQL query builder. From 0.26.0 to 0.28.16, DefaultQueryCompiler.visitJSONPathLeg does not escape JSON-path metacharacters (., [, ], *, **, ?). When attacker-controlled input flows into eb.ref(col, '->$').key(input) or .at(input) — including type-safe code where the JSON column is shaped like Record<string, T> so K extends string is the inferred type — every dot becomes a path-leg separator, letting an attacker traverse from the intended key into sibling and child fields the developer never meant to expose. The result is read access (and, in update statements, write access) to JSON sub-fields outside the intended scope across MySQL, PostgreSQL ->$/->>$, and SQLite. This vulnerability is fixed in 0.28.17.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

0.36%Up 0.3 points since May 28, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.5

Kysely: JSON-path traversal injection via unsanitized path-leg metacharacters in `JSONPathBuilder.key()` / `.at()`

Kysely is a type-safe TypeScript SQL query builder. From 0.26.0 to 0.28.16, DefaultQueryCompiler.visitJSONPathLeg does not escape JSON-path metacharacters (., [, ], *, **, ?). When attacker-controlled input flows into eb.ref(col, '->$').key(input) or .at(input) — including type-safe code where the JSON column is shaped like Record<string, T> so K extends string is the inferred type — every dot becomes a path-leg separator, letting an attacker traverse from the intended key into sibling and child fields the developer never meant to expose. The result is read access (and, in update statements, write access) to JSON sub-fields outside the intended scope across MySQL, PostgreSQL ->$/->>$, and SQLite. This vulnerability is fixed in 0.28.17.

Record
CVE-2026-44635
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-89, CWE-915, CWE-1284
Updated
2026-11-02
EUVDEUVD-2026-32623 7.5

Kysely is a type-safe TypeScript SQL query builder. From 0.26.0 to 0.28.16, DefaultQueryCompiler.visitJSONPathLeg does not escape JSON-path metacharacters (., [, ], *, **, ?). When attacker-controlled input flows into eb.ref(col, '->$').key(input) or .at(input) — including type-safe code where the JSON column is shaped like Record<string, T> so K extends string is the inferred type — every dot becomes a path-leg separator, letting an attacker traverse from the intended key into sibling and child fields the developer never meant to expose. The result is read access (and, in update statements, write access) to JSON sub-fields outside the intended scope across MySQL, PostgreSQL ->$/->>$, and SQLite. This vulnerability is fixed in 0.28.17.

Record
EUVD-2026-32623
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-pv5w-4p9q-p3v2 7.5

Kysely: JSON-path traversal injection via unsanitized path-leg metacharacters in `JSONPathBuilder.key()` / `.at()`

Summary

Kysely 0.28.12 added a sanitizeStringLiteral() call inside DefaultQueryCompiler.visitJSONPathLeg (commit 0a602bf, PR #1727) to fix CVE-2026-32763 (GHSA-wmrf-hv6w-mr66). The fix only doubles single quotes (' → ''); it does not escape JSON-path metacharacters (., [, ], *, **, ?). When attacker-controlled input flows into eb.ref(col, '->$').key(input) or .at(input) — including type-safe code where the JSON column is shaped like Record<string, T> so K extends string is the inferred type — every dot becomes a path-leg separator, letting an attacker traverse from the intended key into sibling and child fields the developer never meant to expose. The result is read access (and, in update statements, write access) to JSON sub-fields outside the intended scope across MySQL, PostgreSQL ->$/->>$, and SQLite.

  • Project: Kysely — TypeScript SQL query builder (npm kysely); affects MySQL, PostgreSQL ->$/->>$, and SQLite dialects.
  • Source reviewed: kysely-org/kysely @ master (73192e4, version 0.28.16).
  • Deployed artefact validated: [email protected] from npm.
  • Affected file(s):
    • src/query-compiler/default-query-compiler.ts (lines 1611–1639, 1821–1823)
    • src/query-builder/json-path-builder.ts (lines 93–196)
    • src/dialect/mysql/mysql-query-compiler.ts (overrides sanitizeStringLiteral but inherits the same behaviour for path legs — escapes \ and ', nothing else)
  • CWE: CWE-89 — Improper Neutralization of Special Elements used in an SQL Command, with CWE-915 / CWE-1284 (improper validation of specified quantity in input) flavours for the JSON-path sub-language.
  • OWASP 2021: A03:2021 — Injection.

Vulnerable code

src/query-compiler/default-query-compiler.ts:1625-1639:

protected override visitJSONPathLeg(node: JSONPathLegNode): void {
  const isArrayLocation = node.type === 'ArrayLocation'

  this.append(isArrayLocation ? '[' : '.')      // (1)

  this.append(
    typeof node.value === 'string'
      ? this.sanitizeStringLiteral(node.value)  // (2)
      : String(node.value),
  )

  if (isArrayLocation) {
    this.append(']')
  }
}

src/query-compiler/default-query-compiler.ts:1821-1823:

protected sanitizeStringLiteral(value: string): string {
  return value.replace(LIT_WRAP_REGEX, "''")    // (3)
}

with LIT_WRAP_REGEX = /'/g.

src/query-builder/json-path-builder.ts:151-167:

key<
  K extends any[] extends O
    ? never
    : O extends object
      ? keyof NonNullable<O> & string
      : never,
  O2 = undefined extends O
    ? null | NonNullable<NonNullable<O>[K]>
    : null extends O
      ? null | NonNullable<NonNullable<O>[K]>
      : // when the object has non-specific keys, e.g. Record<string, T>, should infer `T | null`!
        string extends keyof NonNullable<O>
        ? null | NonNullable<NonNullable<O>[K]>
        : NonNullable<O>[K],
>(key: K): TraversedJSONPathBuilder<S, O2> {
  return this.#createBuilderWithPathLeg('Member', key)  // (4)
}

src/query-builder/json-path-builder.ts:169-196:

#createBuilderWithPathLeg(
  legType: JSONPathLegType,
  value: string | number,                                // (5)
): TraversedJSONPathBuilder<any, any> {
  // ...
  return new TraversedJSONPathBuilder(
    JSONPathNode.cloneWithLeg(
      this.#node,
      JSONPathLegNode.create(legType, value),            // (6)
    ),
  )
}

At (1) the compiler emits the path-leg separator — . for member access or [ for array index. At (2) the user-supplied string is run through sanitizeStringLiteral, which at (3) only doubles single quotes ('). Dots, brackets, asterisks, double-asterisks and question marks — every reserved character of the SQL/JSON path mini-language — pass through unmodified.

At (4) .key(K) types K as keyof NonNullable<O> & string. When the JSON column is typed as Record<string, T> (a common shape for free-form metadata blobs) the inferred K is just…

Record
GHSA-pv5w-4p9q-p3v2
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-89, CWE-915, CWE-1284
Updated
2026-11-02
NVD 7.5

Kysely is a type-safe TypeScript SQL query builder. From 0.26.0 to 0.28.16, DefaultQueryCompiler.visitJSONPathLeg does not escape JSON-path metacharacters (., [, ], *, **, ?). When attacker-controlled input flows into eb.ref(col, '->$').key(input) or .at(input) — including type-safe code where the JSON column is shaped like Record<string, T> so K extends string is the inferred type — every dot becomes a path-leg separator, letting an attacker traverse from the intended key into sibling and child fields the developer never meant to expose. The result is read access (and, in update statements, write access) to JSON sub-fields outside the intended scope across MySQL, PostgreSQL ->$/->>$, and SQLite. This vulnerability is fixed in 0.28.17.

Record
CVE-2026-44635
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-89, CWE-915, CWE-1284
Updated
2026-11-02
OSV 7.5

Kysely: JSON-path traversal injection via unsanitized path-leg metacharacters in `JSONPathBuilder.key()` / `.at()`

Kysely is a type-safe TypeScript SQL query builder. From 0.26.0 to 0.28.16, DefaultQueryCompiler.visitJSONPathLeg does not escape JSON-path metacharacters (., [, ], *, **, ?). When attacker-controlled input flows into eb.ref(col, '->$').key(input) or .at(input) — including type-safe code where the JSON column is shaped like Record<string, T> so K extends string is the inferred type — every dot becomes a path-leg separator, letting an attacker traverse from the intended key into sibling and child fields the developer never meant to expose. The result is read access (and, in update statements, write access) to JSON sub-fields outside the intended scope across MySQL, PostgreSQL ->$/->>$, and SQLite. This vulnerability is fixed in 0.28.17.

Record
CVE-2026-44635
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-1284, CWE-22, CWE-89, CWE-915
Updated
2026-11-02
OSVGHSA-pv5w-4p9q-p3v2 7.5

Kysely: JSON-path traversal injection via unsanitized path-leg metacharacters in `JSONPathBuilder.key()` / `.at()`

Summary

Kysely 0.28.12 added a sanitizeStringLiteral() call inside DefaultQueryCompiler.visitJSONPathLeg (commit 0a602bf, PR #1727) to fix CVE-2026-32763 (GHSA-wmrf-hv6w-mr66). The fix only doubles single quotes (' → ''); it does not escape JSON-path metacharacters (., [, ], *, **, ?). When attacker-controlled input flows into eb.ref(col, '->$').key(input) or .at(input) — including type-safe code where the JSON column is shaped like Record<string, T> so K extends string is the inferred type — every dot becomes a path-leg separator, letting an attacker traverse from the intended key into sibling and child fields the developer never meant to expose. The result is read access (and, in update statements, write access) to JSON sub-fields outside the intended scope across MySQL, PostgreSQL ->$/->>$, and SQLite.

  • Project: Kysely — TypeScript SQL query builder (npm kysely); affects MySQL, PostgreSQL ->$/->>$, and SQLite dialects.
  • Source reviewed: kysely-org/kysely @ master (73192e4, version 0.28.16).
  • Deployed artefact validated: [email protected] from npm.
  • Affected file(s):
    • src/query-compiler/default-query-compiler.ts (lines 1611–1639, 1821–1823)
    • src/query-builder/json-path-builder.ts (lines 93–196)
    • src/dialect/mysql/mysql-query-compiler.ts (overrides sanitizeStringLiteral but inherits the same behaviour for path legs — escapes \ and ', nothing else)
  • CWE: CWE-89 — Improper Neutralization of Special Elements used in an SQL Command, with CWE-915 / CWE-1284 (improper validation of specified quantity in input) flavours for the JSON-path sub-language.
  • OWASP 2021: A03:2021 — Injection.

Vulnerable code

src/query-compiler/default-query-compiler.ts:1625-1639:

protected override visitJSONPathLeg(node: JSONPathLegNode): void {
  const isArrayLocation = node.type === 'ArrayLocation'

  this.append(isArrayLocation ? '[' : '.')      // (1)

  this.append(
    typeof node.value === 'string'
      ? this.sanitizeStringLiteral(node.value)  // (2)
      : String(node.value),
  )

  if (isArrayLocation) {
    this.append(']')
  }
}

src/query-compiler/default-query-compiler.ts:1821-1823:

protected sanitizeStringLiteral(value: string): string {
  return value.replace(LIT_WRAP_REGEX, "''")    // (3)
}

with LIT_WRAP_REGEX = /'/g.

src/query-builder/json-path-builder.ts:151-167:

key<
  K extends any[] extends O
    ? never
    : O extends object
      ? keyof NonNullable<O> & string
      : never,
  O2 = undefined extends O
    ? null | NonNullable<NonNullable<O>[K]>
    : null extends O
      ? null | NonNullable<NonNullable<O>[K]>
      : // when the object has non-specific keys, e.g. Record<string, T>, should infer `T | null`!
        string extends keyof NonNullable<O>
        ? null | NonNullable<NonNullable<O>[K]>
        : NonNullable<O>[K],
>(key: K): TraversedJSONPathBuilder<S, O2> {
  return this.#createBuilderWithPathLeg('Member', key)  // (4)
}

src/query-builder/json-path-builder.ts:169-196:

#createBuilderWithPathLeg(
  legType: JSONPathLegType,
  value: string | number,                                // (5)
): TraversedJSONPathBuilder<any, any> {
  // ...
  return new TraversedJSONPathBuilder(
    JSONPathNode.cloneWithLeg(
      this.#node,
      JSONPathLegNode.create(legType, value),            // (6)
    ),
  )
}

At (1) the compiler emits the path-leg separator — . for member access or [ for array index. At (2) the user-supplied string is run through sanitizeStringLiteral, which at (3) only doubles single quotes ('). Dots, brackets, asterisks, double-asterisks and question marks — every reserved character of the SQL/JSON path mini-language — pass through unmodified.

At (4) .key(K) types K as keyof NonNullable<O> & string. When the JSON column is typed as Record<string, T> (a common shape for free-form metadata blobs) the inferred K is just…

Record
GHSA-pv5w-4p9q-p3v2
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-1284, CWE-22, CWE-89, CWE-915
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
kysely
npm
0.26.0 up to 0.28.17
0.28.17

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-44635 is a high vulnerability (CVSS 7.5) in Kysely-org Kysely, published May 11, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.36%, the 30th percentile. Fixed in kysely 0.28.17.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open