CVE-2026-104584 Security Alert: CRITICAL Vulnerability
Urgent: CVE-2026-104584 requires immediate attention.
· 8 min read
Executive Summary
CVE-2026-104584 is a critical OS command injection flaw in reNgine affecting up to v2.2.0 and the current master branch at de4199222cca5618f1255930ce78987e47d43a99. The issue is triggered through the custom_headers scan engine configuration field in web/reNgine/tasks.py, specifically in the fetch_url and dir_file_fuzz functions. An attacker who can influence scan configuration or inputs may be able to execute arbitrary shell commands on the host running reNgine.
There is no known exploitation in the wild and it is not in CISA KEV at this time, but the severity is CVSS 9.8. For solo developers and small teams, the practical risk is high because a single compromised scan job or exposed admin panel can lead to full server takeover.
Immediate Action
- Upgrade immediately to a fixed release as soon as the vendor publishes one. If no patched version is available yet, disable the affected scan engine path or remove access to the configuration field that accepts
custom_headers. - Isolate the service: run reNgine in a locked-down container or VM with no shell access, minimal filesystem permissions, and restricted outbound network access.
- Rollback risky deployments: if you recently deployed
v2.2.0or a build from currentmaster, revert to a known-safe build only if you have verified that the vulnerable code path is removed or disabled. - Restrict who can edit scan configs: limit admin/UI/API access to trusted users only, and rotate credentials if the panel was exposed.
- Review vendor guidance and monitor for a patch notice: Vendor advisory / release notes.
Affected Versions
reNgine@<=2.2.0vulnerablereNgine@masterat commitde4199222cca5618f1255930ce78987e47d43a99vulnerablereNgine@TODO_FIXED_VERSIONand later: safe only if confirmed by vendor release notesreNgine@TODO_PATCH_COMMITand later: safe only if confirmed by code review
Resolution Guide
Python / pip
# Upgrade to the first patched release once published
pip install --upgrade reNgine==TODO_FIXED_VERSION
# If installed in a virtualenv, update there too
python -m pip install --upgrade reNgine==TODO_FIXED_VERSION
pipx
pipx upgrade reNgine
# If a specific fixed version is required:
pipx install reNgine==TODO_FIXED_VERSION --force
Docker
# Stop using vulnerable tags
docker pull rengine/TODO_SAFE_IMAGE:TODO_FIXED_TAG
# Example rollback/replace flow
docker stop rengine
docker rm rengine
docker run -d --name rengine \
--read-only \
--cap-drop ALL \
--security-opt no-new-privileges \
rengine/TODO_SAFE_IMAGE:TODO_FIXED_TAG
apt / yum
# If packaged by your distro or internal repo
sudo apt update
sudo apt install --only-upgrade rengine=TODO_FIXED_VERSION
# RHEL/Fedora/CentOS-style
sudo yum update rengine- TODO_FIXED_VERSION
npm / yarn / pnpm
# Not typically applicable to reNgine itself, but included for teams wrapping it in JS tooling
npm i reNgine@TODO_FIXED_VERSION
yarn add reNgine@TODO_FIXED_VERSION
pnpm add reNgine@TODO_FIXED_VERSION
Maven / Gradle
// Not typically applicable to reNgine itself, but useful if embedded in JVM automation
// Maven: set the dependency to TODO_FIXED_VERSION
// Gradle: implementation("...:TODO_FIXED_VERSION")
Hardening / feature disablement
# Disable the vulnerable scan path if your deployment supports feature flags
export RENGINE_DISABLE_CUSTOM_HEADERS=1
# Or block the field at the reverse proxy / API layer
# Example: reject requests containing custom_headers in scan configuration payloads
Minimal code fix example
# web/reNgine/tasks.py
# Before: user-controlled custom_headers may reach shell execution
# After: sanitize and avoid shell=True
import shlex
import subprocess
def safe_headers(headers: str) -> str:
# Allow only a narrow character set or parse structured JSON instead
allowed = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:;,. /")
if any(ch not in allowed for ch in headers):
raise ValueError("Invalid custom_headers")
return headers
def run_command(url, custom_headers):
headers = safe_headers(custom_headers)
subprocess.run(
["curl", "-H", headers, url],
check=True,
shell=False,
)
Detection & Verification
Check version and commit
git rev-parse HEAD
git log -1 --oneline
python -m pip show reNgine
docker image inspect rengine/TODO_IMAGE:TAG --format '{{.RepoTags}}'
Search for the vulnerable code path
grep -RIn "custom_headers" web/reNgine/tasks.py
grep -RIn "shell=True" web/reNgine/tasks.py
grep -RIn "fetch_url\|dir_file_fuzz" web/reNgine/tasks.py
Check whether your deployment exposes the risky field
# Look for API/UI references, forms, or serializers that accept custom_headers
grep -RIn "custom_headers" .
Dependency and image audit
# Python dependency audit
pip-audit
python -m pip check
# Container scan
trivy image rengine/TODO_IMAGE:TAG
grype rengine/TODO_IMAGE:TAG
Verify the fix
# Confirm the patched build no longer contains the vulnerable pattern
grep -RIn "shell=True" web/reNgine/tasks.py
# Run a harmless test payload and ensure it is rejected
# Example expected result: validation error, no command execution, no outbound shell activity
Risk and Impact
If exploited, this bug can give an attacker remote command execution on the reNgine host. That can mean stolen scan data, tampered results, credential theft, persistence, and lateral movement into the rest of your environment. For small teams, the blast radius is often the entire server, the connected database, and any secrets stored in environment variables or mounted config files.
Because reNgine is often used with elevated access to perform reconnaissance tasks, treat this as a full compromise risk until you have patched, isolated, and verified the deployment.