name: audit-subprocess description: Scan backend services for subprocess bugs — missing sudo, missing exception handling on distro-specific commands, raw subprocess calls bypassing system utilities, and container/environment assumptions that break in LXC or restricted environments. Reports issues with file, line, and fix. argument-hint: "[file-or-directory]"
Audit subprocess calls in ServerKit backend services for recurring bug patterns. Scope: ${ARGUMENTS:-backend/app/services/}
What to Scan For
Pattern 1: Missing sudo on privileged commands
Search for subprocess.run() calls that invoke commands requiring root but lack sudo:
systemctl(start, stop, restart, enable, disable, daemon-reload) — ALL require sudofirewall-cmd(--state, --get-default-zone, --list-services, --list-ports, --list-rich-rules, --get-zones, --zone=, --add-, --remove-*, --reload) — ALL require sudoufw(status, enable, disable, allow, deny, delete) — ALL require sudoiptables/ip6tables— ALL require sudonginx(-s reload, -t) — ALL require sudocertbot— ALL require sudofreshclam— requires sudo
For each match, check if the command list starts with 'sudo'. If not, flag it.
Ignore: Commands that legitimately don't need sudo (git, python, pip, npm, node, which, cat, ls, grep, df, free, uptime, whoami, hostname, lsb_release).
Pattern 2: Missing exception handling on distro-specific commands
Search for subprocess.run() calls that use distro-specific package managers without try/except FileNotFoundError:
dpkg— Debian/Ubuntu only, doesn't exist on RHEL/Fedora/CentOSapt/apt-get— Debian/Ubuntu onlyrpm— RHEL family only, doesn't exist on Debiandnf/yum— RHEL family only
For each match, check if it's wrapped in a try/except that catches FileNotFoundError (or a broad Exception on the immediate call). If not, flag it.
Acceptable: If the call is guarded by os.path.exists('/usr/bin/<cmd>') before the subprocess call, that's fine — don't flag it.
Pattern 3: Raw subprocess calls that should use system utilities
The project provides centralized utilities in app/utils/system.py. Flag direct subprocess calls that bypass them:
subprocess.run(['sudo', 'systemctl', ...])→ should useServiceControl.start/stop/restart/reload/enable/disable/daemon_reload()subprocess.run(['systemctl', 'is-active', ...])→ should useServiceControl.is_active()subprocess.run(['systemctl', 'is-enabled', ...])→ should useServiceControl.is_enabled()subprocess.run(['dpkg', ...])orsubprocess.run(['rpm', ...])for package checks → should usePackageManager.is_installed()os.path.exists('/usr/bin/apt')or similar distro detection → should usePackageManager.detect()for path in ['/usr/bin/X', '/usr/sbin/X']: if os.path.exists(path)binary search → should useis_command_available()subprocess.run(['sudo', 'apt-get', 'install', ...])or['sudo', 'dnf', 'install', ...]→ should usePackageManager.install()subprocess.run(['sudo', <privileged-cmd>, ...])for other privileged commands → should userun_privileged()
Acceptable exceptions (do NOT flag these):
- Docker CLI calls in
docker_service.py(uses Docker socket) - Git CLI calls (no privilege needed)
- Python/pip in venvs (per-app, no root)
- MySQL/PostgreSQL CLI (auth via socket/password)
- WP-CLI (
sudo -u www-datapattern) - Read-only commands (
clamscan,fail2ban-client status,uname,which,ssh-keygen, etc.)
Pattern 4: Container/environment assumptions
Code that assumes bare-metal or KVM and breaks inside LXC containers, Docker, or restricted environments. Search for these patterns:
4a. Unguarded /proc and /sys reads
open('/proc/cpuinfo')or similar/proc/reads withouttry/except (FileNotFoundError, PermissionError)open('/sys/class/...')or/sys/reads — often restricted in unprivileged containers/proc/meminfo,/proc/net/,/proc/diskstats— may be empty or permission-denied
Flag if the read is NOT wrapped in a try/except that handles FileNotFoundError or PermissionError.
4b. psutil calls that fail in containers
psutil.disk_io_counters()— returnsNonewhen/proc/diskstatsis unavailablepsutil.disk_partitions()— returns container-internal mounts, not host diskspsutil.sensors_temperatures()— fails without/sys/class/thermal/psutil.sensors_fans()— same issuepsutil.net_io_counters(pernic=True)— may show veth interfaces only
Flag if the return value is used without a None / empty check. For example, psutil.disk_io_counters().read_bytes will crash if the call returns None.
4c. Docker socket assumptions
subprocess.run(['docker', ...])without checking if Docker is installed/running first- Direct access to
/var/run/docker.sockwithout verifying the socket exists - Any Docker operation that doesn't handle
FileNotFoundErrororConnectionError
Flag if there's no pre-check (e.g., is_docker_installed()) or no try/except around the call.
Acceptable: Calls inside docker_service.py that are already gated behind is_docker_installed() at the API layer.
4d. Firewall/network commands without capability checks
firewall-cmd,ufw,iptables— requireCAP_NET_ADMINwhich is dropped in unprivileged LXC- These commands fail silently or with cryptic errors when capabilities are missing
Flag if the subprocess call doesn't handle the failure case (no try/except, or no check of returncode).
4e. Hardcoded device paths
/dev/references (e.g.,/dev/sda,/dev/nullis fine) — block devices don't exist in containers/dev/fuse— FUSE device, unavailable in unprivileged LXC
Flag hardcoded /dev/ paths (except /dev/null, /dev/stdin, /dev/stdout, /dev/stderr, /dev/urandom, /dev/random).
Acceptable: Paths discovered dynamically from psutil or lsblk output.
How to Audit
- Use Grep to find all
subprocess.run(calls in the target scope - For each match, read the surrounding context (5-10 lines) to check:
- Is
sudopresent for privileged commands? - Is there a
try/except FileNotFoundErrorfor distro-specific commands? - Is there an
os.path.exists()guard? - Is there a system utility (
ServiceControl,PackageManager,run_privileged,is_command_available) that should be used instead?
- Is
- Also search for
os.path.exists('/usr/bin/apt')and similar distro-detection patterns - Search for
open('/proc/andopen('/sys/— check for missing error handling - Search for
psutil.disk_io_counters,psutil.disk_partitions,psutil.sensors_— check return values are guarded againstNone - Search for
/dev/string literals — flag hardcoded device paths (except standard ones) - Search for
dockersubprocess calls outsidedocker_service.py— check for availability guards - For firewall commands, check that
returncodeis inspected or the call is wrapped in try/except - Collect all violations
Report Format
For each issue found, report:
[PATTERN] file_path:line_number
Command: ['systemctl', 'restart', ...]
Fix: Add 'sudo' as first element
or for Pattern 3:
[PATTERN 3] file_path:line_number
Command: subprocess.run(['sudo', 'systemctl', 'restart', service], ...)
Fix: Use ServiceControl.restart(service)
Then provide a summary:
## Summary
- Files scanned: X
- Total subprocess calls: X
- Missing sudo: X instances across Y files
- Missing exception handling: X instances across Y files
- Should use system utilities: X instances across Y files
- Container/environment assumptions: X instances across Y files
- Clean: X calls
If issues are found, ask the user if they want you to fix them automatically. If no issues are found, confirm the codebase is clean for these patterns.