Lookup for vulnerable packages by Package URL.
| Purl | pkg:npm/%40saltcorn/data@0.6.2-beta.5 |
| Type | npm |
| Namespace | @saltcorn |
| Name | data |
| Version | 0.6.2-beta.5 |
| Qualifiers |
|
| Subpath | |
| Is_vulnerable | true |
| Next_non_vulnerable_version | 1.4.5 |
| Latest_non_vulnerable_version | 1.6.0-beta.4 |
| Affected_by_vulnerabilities |
| 0 |
| url |
VCID-pfz1-y9nf-7fd7 |
| vulnerability_id |
VCID-pfz1-y9nf-7fd7 |
| summary |
@saltcorn/data vulnerable to SQL Injection via jsexprToSQL Literal Handler
## 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
<img width="1194" height="559" alt="SCR-20260307-edqn" src="https://github.com/user-attachments/assets/a2d11102-f49b-4b2b-88ff-fced37476b6f" />
2. Go to the table and then to `Constraits`
<img width="1180" height="600" alt="SCR-20260307-edsg" src="https://github.com/user-attachments/assets/b55ddace-01be-4a53-8f62-cbec98172cd7" />
3. Go to `Formula`
<img width="1130" height="518" alt="SCR-20260307-edud" src="https://github.com/user-attachments/assets/8a5addc6-e681-401b-91ea-bce3b0eece54" />
4. Create a test table for verification
<img width="857" height="294" alt="SCR-20260307-eetw" src="https://github.com/user-attachments/assets/debc8581-8145-44cb-a684-2bc3eb7adbcf" />
5. Input the payload and save
<img width="763" height="383" alt="SCR-20260307-ehcz" src="https://github.com/user-attachments/assets/f7a3aa34-7b0b-48ea-b1df-f852f137c37f" />
6. Check the table for testing
<img width="549" height="256" alt="SCR-20260307-ehuh" src="https://github.com/user-attachments/assets/8f6da842-0275-4729-93bf-96575f3fe963" />
## 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. |
| references |
|
| fixed_packages |
|
| aliases |
GHSA-59xv-588h-2vmm
|
| risk_score |
1.4 |
| exploitability |
0.5 |
| weighted_severity |
2.7 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-pfz1-y9nf-7fd7 |
|
| 1 |
| url |
VCID-xqes-aykm-17d8 |
| vulnerability_id |
VCID-xqes-aykm-17d8 |
| summary |
@saltcorn/data: Tenant user role is used for tenant creation role check
## Summary
When a tenant admin is logged out of the root domain (e.g., saltcorn.com) but logged in to their own tenant space as admin, they can simply append `/tenant/create` to their tenant URL. The system reads the role from the tenant context (admin), and a new tenant is created on the **root domain** (in `PUBLIC SCHEMA > _sc_tenants`), rather than in the tenant's own `_sc_tenants` table.
If the same logic applies to other routes, a tenant admin effectively gains admin rights on the root domain.
## PoC
A tenant-created subtenant appears under the Saltcorn public schema instead of the tenant's own schema.
- Even when `role_id=1` is required for tenant creation on saltcorn.com (only admin can create tenants), existing tenant admins can still create new tenants because their local `role_id:1` is evaluated against the root domain.
- Even when `role_to_create_tenant` is set to `0` in the tenant's `_sc_config` schema, or removed entirely, the tenant admin can still create sub-tenants on the root domain — suggesting `role_to_create_tenant` is not being read at all.
## Impact
Tenant admins gain unauthorized admin-level access to the root domain. Any authenticated tenant admin can perform privileged operations (e.g., creating tenants) on the root domain by exploiting the role context mismatch. |
| references |
|
| fixed_packages |
|
| aliases |
GHSA-9237-rg5p-rhfw
|
| risk_score |
4.0 |
| exploitability |
0.5 |
| weighted_severity |
8.0 |
| resource_url |
http://public2.vulnerablecode.io/vulnerabilities/VCID-xqes-aykm-17d8 |
|
|
| Fixing_vulnerabilities |
|
| Risk_score | 4.0 |
| Resource_url | http://public2.vulnerablecode.io/packages/pkg:npm/%2540saltcorn/data@0.6.2-beta.5 |