{"answers":{"affected":"6 open source packages ship an affected version, including @saltcorn/data.","exploited":"There is no known exploitation of GHSA-59xv-588h-2vmm in the wild and no public exploit code.","fix":"Upgrade @saltcorn/data to a fixed version for your release line: 1.4.5, 1.5.5 or 1.6.0-beta.4.","what":"GHSA-59xv-588h-2vmm is a SQL injection vulnerability in @saltcorn/data, published on 10 Apr 2026. An attacker needs administrator access to exploit it, and only if a user opens a file or follows a link."},"fix_prompt":"Check this codebase for GHSA-59xv-588h-2vmm and fix it if it is affected.\n\nWhat it is: GHSA-59xv-588h-2vmm is a SQL injection vulnerability in @saltcorn/data, published on 10 Apr 2026. An attacker needs administrator access to exploit it, and only if a user opens a file or follows a link.\nExploitation: There is no known exploitation of GHSA-59xv-588h-2vmm in the wild and no public exploit code.\n\nAffected packages and fixed versions:\n- @saltcorn/data (npm): affected all versions; fixed in 1.4.5\n- @saltcorn/data (npm): affected all versions; fixed in 1.4.5\n- @saltcorn/data (npm): affected from 1.5.0; fixed in 1.5.5\n- @saltcorn/data (npm): affected from 1.5.0; fixed in 1.5.5\n- @saltcorn/data (npm): affected from 1.6.0-alpha.0; fixed in 1.6.0-beta.4\n- @saltcorn/data (npm): affected from 1.6.0-alpha.0; fixed in 1.6.0-beta.4\n\nTask:\n1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.\n2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.\n3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.\n4. Run the tests and summarise what changed and why.\n5. If nothing in the project is affected, say so and change nothing.\n\nReference: https://insights.sbomify.com/GHSA-59xv-588h-2vmm/ (Markdown: https://insights.sbomify.com/GHSA-59xv-588h-2vmm/index.md)","id":"GHSA-59xv-588h-2vmm","markdown":"https://insights.sbomify.com/GHSA-59xv-588h-2vmm/index.md","name":"GHSA-59xv-588h-2vmm","record":{"aliases":[],"analysis":{"component_type":"web_application","fix_type":"patch","impacts":["data_read","data_modify"],"network_reachable":"yes","non_default_config":false,"product_category":"Saltcorn data library","requires_auth":"high_privilege","summary":"An admin can inject SQL via unescaped string literals in Formula constraints, allowing unauthorized database modification or data access.","user_interaction":"required","vuln_class":"sql_injection"},"analysis_generated_by":"qwen3.8-flash-next","assigner":null,"cpe":[],"cvss":{"score":null,"severity":null,"source":null,"vector":null,"version":null},"cwes":[],"description":"## Summary\n\nThe `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.\n\n## Vulnerable Component\n\n**File:** `packages/saltcorn-data/models/expression.ts`, lines 117-118\n\n```typescript\nLiteral({ value }: { value: ExtendedNode }) {\n  if (typeof value == \"string\") return `'${value}'`;  // NO ESCAPING!\n  return `${value}`;\n},\n```\n\n**Call chain:** Formula constraint creation → `table_constraints.ts:127` → `jsexprToSQL()` → `Literal()` → `db.query()` executes unsanitized SQL.\n\n## Proof of Concept\n\n### Injection via Formula Constraint\n\nWhen an admin creates a Formula-type table constraint with the expression:\n\n```javascript\nname === \"test' OR '1'='1\"\n```\n\nThe `jsexprToSQL()` function generates:\n\n```sql\n(name)=('test' OR '1'='1')\n```\n\nThis is then executed as:\n\n```sql\nALTER TABLE \"tablename\" ADD CONSTRAINT \"tablename_fml_1\" CHECK ((name)=('test' OR '1'='1'));\n```\n\nThe single quote in the string literal is not escaped, breaking out of the SQL string context.\n\n### More Dangerous Payload\n\n```javascript\nname === \"'; DROP TABLE users; --\"\n```\n\nGenerates:\n\n```sql\n(name)=(''; DROP TABLE users; --')\n```\n\n### Verified on Saltcorn v1.5.0 (Docker)\n\nDirect invocation of `jsexprToSQL()` inside the running container confirms the vulnerability:\n\n```\nInput:  name === \"hello\"\nOutput: (name)=('hello')                          ← Normal\n\nInput:  name === \"test' OR '1'='1\"\nOutput: (name)=('test' OR '1'='1')                ← Single quote NOT escaped, OR injected\n\nInput:  name === \"'; DROP TABLE users; --\"\nOutput: (name)=(''; DROP TABLE users; --')         ← DROP TABLE injected\n```\n\nThe test was performed on a completely fresh Saltcorn installation (zero user-created tables, default Docker setup).\n\n### PoC Screenshot\n\n1. Create a table after moving to the table menu\n\n\u003cimg width=\"1194\" height=\"559\" alt=\"SCR-20260307-edqn\" src=\"https://github.com/user-attachments/assets/a2d11102-f49b-4b2b-88ff-fced37476b6f\" /\u003e\n\n2. Go to the table and then to `Constraits`\n\n\u003cimg width=\"1180\" height=\"600\" alt=\"SCR-20260307-edsg\" src=\"https://github.com/user-attachments/assets/b55ddace-01be-4a53-8f62-cbec98172cd7\" /\u003e\n\n3. Go to `Formula`\n\n\u003cimg width=\"1130\" height=\"518\" alt=\"SCR-20260307-edud\" src=\"https://github.com/user-attachments/assets/8a5addc6-e681-401b-91ea-bce3b0eece54\" /\u003e\n\n4. Create a test table for verification\n\n\u003cimg width=\"857\" height=\"294\" alt=\"SCR-20260307-eetw\" src=\"https://github.com/user-attachments/assets/debc8581-8145-44cb-a684-2bc3eb7adbcf\" /\u003e\n\n5. Input the payload and save\n\n\u003cimg width=\"763\" height=\"383\" alt=\"SCR-20260307-ehcz\" src=\"https://github.com/user-attachments/assets/f7a3aa34-7b0b-48ea-b1df-f852f137c37f\" /\u003e\n\n6. Check the table for testing\n\n\u003cimg width=\"549\" height=\"256\" alt=\"SCR-20260307-ehuh\" src=\"https://github.com/user-attachments/assets/8f6da842-0275-4729-93bf-96575f3fe963\" /\u003e\n\n## Impact\n\n- Arbitrary SQL execution via crafted CHECK constraints\n- Data exfiltration through error-based or time-based SQL injection\n- Database schema manipulation (DROP TABLE, ALTER TABLE)\n- Potential privilege escalation via direct `users` table modification\n\n## Suggested Remediation\n\nEscape single quotes in the `Literal` handler:\n\n```typescript\nLiteral({ value }: { value: ExtendedNode }) {\n  if (typeof value == \"string\") return `'${value.replace(/'/g, \"''\")}'`;\n  return `${value}`;\n},\n```\n\nAlternatively, use parameterized queries for constraint creation instead of string interpolation.","ecosystems":["npm"],"exploits":{"exploitdb":null,"first_seen":null,"github_poc":null,"max_poc_stars":null,"metasploit":null,"nuclei":null,"refs":[],"tier":null},"has_fix":true,"headline":"@saltcorn/data vulnerable to SQL Injection via jsexprToSQL Literal Handler","id":"GHSA-59xv-588h-2vmm","indexable":true,"kev":null,"kind":"advisory","links":{"ecosystem":"npm","product":null,"products":[],"type":"sql_injection","year":"2026"},"n_packages":6,"n_references":null,"packages":[{"ecosystem":"npm","fixed":["1.4.5"],"introduced":["0"],"last_affected":[],"package":"@saltcorn/data","purl":null,"source":"GHSA-59xv-588h-2vmm"},{"ecosystem":"npm","fixed":["1.4.5"],"introduced":["0"],"last_affected":[],"package":"@saltcorn/data","purl":"pkg:npm/%40saltcorn/data","source":"GHSA-59xv-588h-2vmm"},{"ecosystem":"npm","fixed":["1.5.5"],"introduced":["1.5.0"],"last_affected":[],"package":"@saltcorn/data","purl":null,"source":"GHSA-59xv-588h-2vmm"},{"ecosystem":"npm","fixed":["1.5.5"],"introduced":["1.5.0"],"last_affected":[],"package":"@saltcorn/data","purl":"pkg:npm/%40saltcorn/data","source":"GHSA-59xv-588h-2vmm"},{"ecosystem":"npm","fixed":["1.6.0-beta.4"],"introduced":["1.6.0-alpha.0"],"last_affected":[],"package":"@saltcorn/data","purl":null,"source":"GHSA-59xv-588h-2vmm"},{"ecosystem":"npm","fixed":["1.6.0-beta.4"],"introduced":["1.6.0-alpha.0"],"last_affected":[],"package":"@saltcorn/data","purl":"pkg:npm/%40saltcorn/data","source":"GHSA-59xv-588h-2vmm"}],"products":null,"published":"2026-04-10","related":[],"sources":[{"class":"attribution","licence":"CC BY 4.0","name":"GitHub Advisory Database","prefix":"GHSA"}],"ssvc":{"automatable":null,"exploitation":null,"technical_impact":null},"state":null,"updated":null,"vendors":null},"summary":"An admin can inject SQL via unescaped string literals in Formula constraints, allowing unauthorized database modification or data access.","url":"https://insights.sbomify.com/GHSA-59xv-588h-2vmm/"}