Description
A CRITICAL security vulnerability exists in backend/secuscan/executor.py at lines 695–711, combined with disabled-by-default signature enforcement in backend/secuscan/config.py lines 55–56. The executor dynamically imports and executes any parser.py found in a plugin directory using Python's importlib. Plugin signature enforcement is off by default:
# config.py lines 55–56 — enforcement disabled by default
plugin_signature_key: Optional[str] = None
enforce_plugin_signatures: bool = False
Additionally, debug: bool = True is the default, causing get_plugin_manager_for_request() in routes.py:119 to call await init_plugins(settings.plugins_dir) on every API request — a tampered parser is picked up immediately without a server restart.
# executor.py lines 695–711 — parser.py executed with no pre-execution integrity check
if parser_path.exists():
spec = importlib.util.spec_from_file_location(f"parser_{plugin.id}", parser_path)
...
loader.exec_module(module) # arbitrary Python executed here
if hasattr(module, "parse"):
parsed = module.parse(parser_input)
Impact
Any attacker who can write a file to the plugins/<id>/parser.py path achieves immediate arbitrary Python code execution in the context of the backend server process — no authentication, no integrity check, no restart required. The process can read the full SQLite database (all vault credentials), access the local network, install persistence, or exfiltrate data. With no API authentication (see Issue #199), the attack surface for achieving filesystem writes is significantly wider.
Steps to Reproduce
- Overwrite
plugins/nmap/parser.py with:
import subprocess
def parse(output):
subprocess.Popen(["bash", "-c", "id > /tmp/secuscan_pwned"])
return {"findings": []}
- Send any
POST /api/v1/task/start request with plugin_id = "nmap".
- Observed result:
/tmp/secuscan_pwned is created on the server with the output of id, confirming OS-level code execution under the backend process user.
Expected Behaviour
Plugin parsers must be verified with an HMAC signature against a server-held secret key before execution. The application should refuse to load unsigned plugins when enforcement is on, and enforcement should be on by default. Debug-mode hot-reload of plugin code must be disabled.
Proposed Fix
1. Enable enforcement by default:
# backend/secuscan/config.py
enforce_plugin_signatures: bool = True # was False
2. Disable hot-reload of plugins in debug mode:
# backend/secuscan/routes.py
async def get_plugin_manager_for_request():
return get_plugin_manager() # always use the startup-stable instance
3. Re-verify parser integrity immediately before execution:
# backend/secuscan/executor.py — replace dynamic import block
def _load_and_run_parser(self, plugin_id, parser_path, parser_input):
plugin_manager = get_plugin_manager()
plugin = plugin_manager.get_plugin(plugin_id)
plugin_dir = plugin_manager.plugins_dir / plugin_id
# Re-check integrity right before exec — not just at load time
if not plugin_manager._verify_plugin_integrity(plugin, plugin_dir):
raise RuntimeError(f"Parser integrity check failed for {plugin_id}. Refusing execution.")
spec = importlib.util.spec_from_file_location(f"parser_{plugin_id}", parser_path)
if spec and spec.loader:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
if hasattr(module, "parse"):
return module.parse(parser_input)
raise ValueError(f"parser.py for {plugin_id} missing 'parse' function")
4. Document the signing key as required in .env.example:
# REQUIRED for plugin integrity enforcement
SECUSCAN_ENFORCE_PLUGIN_SIGNATURES=true
SECUSCAN_PLUGIN_SIGNATURE_KEY=replace-with-a-signing-key-never-commit-this
Files Affected
backend/secuscan/config.py
backend/secuscan/executor.py
backend/secuscan/routes.py
backend/secuscan/plugins.py
.env.example
Verification
# Tamper with parser.py — backend must detect mismatch and refuse execution
echo "def parse(x): import os; os.system('id')" >> plugins/nmap/parser.py
# Trigger a scan — must log integrity failure and raise RuntimeError, NOT execute the tampered code
# /tmp/secuscan_pwned must NOT be created after the fix is applied
# With SECUSCAN_ENFORCE_PLUGIN_SIGNATURES=true and no key — backend must refuse to start
SECUSCAN_ENFORCE_PLUGIN_SIGNATURES=true python -m uvicorn backend.secuscan.main:app ...
# Expected: error logged, unsigned plugins rejected
Labels
type:security level:advanced gssoc:approved
Please assign this issue to me under GSSoC 2026. I will open a PR with a complete fix covering all affected files, proper test coverage, and verification steps.
Description
A CRITICAL security vulnerability exists in
backend/secuscan/executor.pyat lines 695–711, combined with disabled-by-default signature enforcement inbackend/secuscan/config.pylines 55–56. The executor dynamically imports and executes anyparser.pyfound in a plugin directory using Python'simportlib. Plugin signature enforcement is off by default:Additionally,
debug: bool = Trueis the default, causingget_plugin_manager_for_request()inroutes.py:119to callawait init_plugins(settings.plugins_dir)on every API request — a tampered parser is picked up immediately without a server restart.Impact
Any attacker who can write a file to the
plugins/<id>/parser.pypath achieves immediate arbitrary Python code execution in the context of the backend server process — no authentication, no integrity check, no restart required. The process can read the full SQLite database (all vault credentials), access the local network, install persistence, or exfiltrate data. With no API authentication (see Issue #199), the attack surface for achieving filesystem writes is significantly wider.Steps to Reproduce
plugins/nmap/parser.pywith:POST /api/v1/task/startrequest withplugin_id = "nmap"./tmp/secuscan_pwnedis created on the server with the output ofid, confirming OS-level code execution under the backend process user.Expected Behaviour
Plugin parsers must be verified with an HMAC signature against a server-held secret key before execution. The application should refuse to load unsigned plugins when enforcement is on, and enforcement should be on by default. Debug-mode hot-reload of plugin code must be disabled.
Proposed Fix
1. Enable enforcement by default:
2. Disable hot-reload of plugins in debug mode:
3. Re-verify parser integrity immediately before execution:
4. Document the signing key as required in
.env.example:Files Affected
backend/secuscan/config.pybackend/secuscan/executor.pybackend/secuscan/routes.pybackend/secuscan/plugins.py.env.exampleVerification
Labels
type:securitylevel:advancedgssoc:approvedPlease assign this issue to me under GSSoC 2026. I will open a PR with a complete fix covering all affected files, proper test coverage, and verification steps.