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.0 or a build from current master, 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.0 vulnerable
  • reNgine@master at commit de4199222cca5618f1255930ce78987e47d43a99 vulnerable
  • reNgine@TODO_FIXED_VERSION and later: safe only if confirmed by vendor release notes
  • reNgine@TODO_PATCH_COMMIT and 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.

Keep reading