# Flight vulnerable to SQL Injection via unvalidated identifiers in SimplePdo::insert / update / delete

Flight PHP's SimplePdo insert/update/delete concatenate table names and data-array keys into SQL unquoted, letting attacker-controlled JSON keys inject SQL and create admin rows.

- Payout: Research
- Severity: high
- Program: Flight PHP
- Found by: Rootingg
- Disclosed: 2026-05-06
- CVE: CVE-2026-42550
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-xwqr-rcqg-22mr
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-xwqr-rcqg-22mr
- Tags: area:web domain:web impact:integrity impact:privesc kind:research platform:ghsa sev:high tech:php technique:source-review vuln:sqli

**Target:** SimplePdo query builder (insert/update/delete) in flightphp/core
**Root cause:** SimplePdo::insert/update/delete interpolate the $table argument and array_keys($data) directly into SQL strings with no identifier quoting or validation against a safe-identifier pattern.
**Steps:**
1. Application forwards user data shape to helper: `$db->insert('users', $request->data->getData())`
2. Attacker sends JSON body with malicious key: `{"name, is_admin) VALUES (?, 1);-- ": "attacker_injected"}`
3. Generated SQL becomes `INSERT INTO users (name, is_admin) VALUES (?, 1);-- ) VALUES (?)`, binding the single placeholder to create a row with is_admin=1
4. For update, pass raw $where: `$db->update('users', ['is_admin' => 1], "id = 1 OR 1=1")` flips admin on every row
**How found:** Code review of SimplePdo helpers noting sprintf concatenation of $table and implode of array_keys($data) with no identifier quoting; confirmed by live sqlite repro.
**Exploitation:** Attacker crafts array keys (or $where) reaching insert/update/delete via a documented pattern forwarding request data; injected SQL creates an administrative account in one request or mass-updates rows.
**Escalation:** Privilege escalation to admin account via signup endpoint; arbitrary column write via update keys; data destruction/exfil via $where (DELETE WHERE 1=1, UNION).
**Insight:** When a framework documents forwarding whole request data arrays into query builders, the array keys themselves are attacker-controlled identifiers — test JSON keys containing SQL metacharacters, not just values.

## Proof of concept (copied exactly from the original report)

**Malicious JSON key injecting is_admin on insert**

```
{"name, is_admin) VALUES (?, 1);-- ": "attacker_injected"}
```

**Generated SQL showing injected INSERT statement**

```
INSERT INTO users (name, is_admin) VALUES (?, 1);-- ) VALUES (?)
```

**UPDATE injection via raw where parameter**

```
$db->update('users', ['is_admin' => 1], "id = 1 OR 1=1")
```

