GitHub Advisoryadvisory · npm

GHSA-59xv-588h-2vmm @saltcorn/data vulnerable to SQL Injection via jsexprToSQL Literal Handler

LOW Published 2026-04-10 Modified 2026-04-10 Official page ↗
Ecosystem
npm
Packages
@saltcorn/data
Severity
Low
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:N
Weaknesses
CWE-89
Reviewed
2026-04-10

Affected packages

• npm @saltcorn/data: < 1.4.5 → fixed in 1.4.5 • npm @saltcorn/data: >= 1.5.0, < 1.5.5 → fixed in 1.5.5 • npm @saltcorn/data: >= 1.6.0-alpha.0, < 1.6.0-beta.4 → fixed in 1.6.0-beta.4

Description

Summary The `jsexprToSQL()` function in Saltcorn converts JavaScript expressions to SQL for use in database constraints. The `Literal` handler wraps string values in single quotes without escaping embedded single quotes, allowing SQL injection when creating Formula-type table constraints. Vulnerable Component File: `packages/saltcorn-data/models/expression.ts`, lines 117-118 ```typescript Literal({ value }: { value: ExtendedNode }) { if (typeof value == "string") return `'${value}'`; // NO ESCAPING! return `${value}`; }, ``` Call chain: Formula constraint creation → `table_constraints.ts:127` → `jsexprToSQL()` → `Literal()` → `db.query()` executes unsanitized SQL. Proof of Concept Injection via Formula Constraint When an admin creates a Formula-type table constraint with the expression: ```javascript name === "test' OR '1'='1" ``` The `jsexprToSQL()` function generates: ```sql (name)=('test' OR '1'='1') ``` This is then executed as: ```sql ALTER TABLE "tablename" ADD CONSTRAINT "tablename_fml_1" CHECK ((name)=('test' OR '1'='1')); ``` The single quote in the string literal is not escaped, breaking out of the SQL string context. More Dangerous Payload ```javascript name === "'; DROP TABLE users; --" ``` Generates: ```sql (name)=(''; DROP TABLE users; --') ``` Verified on Saltcorn v1.5.0 (Docker) Direct invocation of `jsexprToSQL()` inside the running container confirms the vulnerability: ``` Input: name === "hello" Output: (name)=('hello') ← Normal Input: name === "test' OR '1'='1" Output: (name)=('test' OR '1'='1') ← Single quote NOT escaped, OR injected Input: name === "'; DROP TABLE users; --" Output: (name)=(''; DROP TABLE users; --') ← DROP TABLE injected ``` The test was performed on a completely fresh Saltcorn installation (zero user-created tables, default Docker setup). PoC Screenshot 1. Create a table after moving to the table menu 2. Go to the table and then to `Constraits` 3. Go to `Formula` 4. Create a test table for verification 5. Input the payload and save 6. Check the table for testing Impact • Arbitrary SQL execution via crafted CHECK constraints • Data exfiltration through error-based or time-based SQL injection • Database schema manipulation (DROP TABLE, ALTER TABLE) • Potential privilege escalation via direct `users` table modification Suggested Remediation Escape single quotes in the `Literal` handler: ```typescript Literal({ value }: { value: ExtendedNode }) { if (typeof value == "string") return `'${value.replace(/'/g, "''")}'`; return `${value}`; }, ``` Alternatively, use parameterized queries for constraint creation instead of string interpolation.

Related

Weakness · CWE (1)

  • CWE-89 Improper Neutralization of Special Elements used in an SQL Command weakness

References