Permissions & System Access Audit — ScorpioX Clang Codebase
Audit Date: 2026-04-28
Auditor: Security Audit Agent
Scope: OS-level permissions, system access, process spawning, privilege model, and sandboxing
Codebase: 148 non-vendor C source files (~125,525 lines) across
scorpiox/ directory
1. Permissions Summary
| Aspect | Assessment | Risk |
|---|
| Root/Privilege Requirements | Optional — most tools run unprivileged; 3 tools require or benefit from root | ⚠️ Medium |
| Process Spawning | Extensive — 42 files spawn child processes via fork(), system(), popen(), execl() | ⚠️ Medium |
| Filesystem Access Scope | Broad — accesses ~/.scorpiox, /tmp, /proc, /sys, /dev, /var, /etc | ⚠️ Medium |
| Kernel/System Calls | Heavy — KVM ioctls, BPF, namespace syscalls, mmap, mount/pivot_root | 🔴 High |
| Sandboxing Model | Strong for containers — user namespaces, pivot_root, overlayfs, cgroups | 🟢 Low |
| IPC Mechanisms | Unix sockets, named pipes, anonymous pipes, signals | ⚠️ Medium |
| Environment Modification | Significant — sets PATH, proxy vars, TLS verification bypass vars | 🔴 High |
2. Privilege Requirements
2.1 Tools That Require Root
| Component | Root Required? | Reason |
|---|
scorpiox-thunderbolt4 | Yes — enforced via geteuid() != 0 check | BPF access for raw Ethernet frames requires root |
scorpiox-dns | Practical yes | Binds to port 53 (privileged port < 1024) by default |
sxmail_smtp | Practical yes | Binds to port 25 (SMTP) — warns "need root?" on failure |
scorpiox-vm | No but needs /dev/kvm access | Suggests sudo usermod -aG kvm $USER on permission denied |
2.2 Tools That Optionally Run as Root
| Component | Root Behavior |
|---|
scorpiox-unshare | Runs rootless by default (user namespaces). --privileged flag skips user namespace (requires running as real root). When root: auto-creates /etc/subuid and /etc/subgid entries, writes UID/GID maps directly, mounts cgroups at /sys/fs/cgroup/ |
scorpiox-wsl | Runs as unprivileged user within WSL; uses chroot within overlayfs |
2.3 Tools That Run Fully Unprivileged
All other ~60+ tools (sx, scorpiox-bash, scorpiox-agent, scorpiox-server, scorpiox-fetch, etc.) run without any elevated privileges. The HTTP server (scorpiox-server) defaults to port 8080 (unprivileged).
2.4 Privileged Helper Dependency
scorpiox-unshare references setuid helpers
/usr/bin/newuidmap and
/usr/bin/newgidmap for non-root multi-UID mapping. These are standard Linux setuid binaries, not shipped with the codebase.
No setuid/setgid/seteuid/setegid calls exist anywhere in the codebase. The code never escalates its own privileges.
3. Process Spawning Inventory
3.1 Process Spawning Frequency
42 source files spawn child processes. Top spawners by call count:
| File | Spawning Calls | Primary Mechanism |
|---|
scorpiox-unshare.c | 31 | clone(), system(), fork() |
scorpiox-agent.c | 19 | system(), execlp(), popen() |
sx.c | 18 | system(), popen() |
scorpiox-wsl.c | 15 | system(), _popen(), CreateProcessA() |
scorpiox-server.c | 13 | fork(), execlp(), popen() |
scorpiox-sdk.c | 13 | system(), fork() |
scorpiox-fetch.c | 12 | system(), fork() |
scorpiox-whatsapp.c | 10 | fork(), execl(), system(), popen() |
3.2 Process Spawning Mechanisms Used
| Mechanism | Usage Context | Risk Notes |
|---|
clone() with CLONE_NEWNS\ | CLONE_NEWPID\ | CLONE_NEWUTS\ | CLONE_NEWUSER\ | CLONE_NEWNET | Container creation in scorpiox-unshare | Core functionality; well-isolated |
fork() + exec*() | Command execution (scorpiox-bash, scorpiox-server, scorpiox-traffic, scorpiox-init, scorpiox-whatsapp) | Standard pattern; generally safe |
system() | 31 call sites across 20+ files — package installation, git operations, network config, tmux commands, editor launch | ⚠️ Shell injection risk if arguments derive from user input without sanitization |
popen() | Command output capture (sx.c, scorpiox-agent.c, scorpiox-hook.c, scorpiox-server.c) | Same injection concerns as system() |
CreateProcessA() | Windows self-restart in scorpiox-wsl.c | Windows-specific; acceptable |
forkpty() / ConPTY | PTY-based execution in sx_pty.c | Needed for terminal emulation |
3.3 Critical system() Call Sites
Several system() calls construct commands from runtime data:
scorpiox-unshare.c:784: snprintf(cmd, ..., "newuidmap %d 0 %d 1 1 %lu %lu", child_pid, ...) — arguments are numeric PIDs/UIDs, low injection risk
scorpiox-unshare.c:1308: Package installation: system(cmd) where cmd contains package names from CONTAINER_PACKAGES env var — ⚠️ unsanitized environment variable input
scorpiox-agent.c:382: system(cmd) for git clone/checkout operations — input from user-provided agent URLs
scorpiox-hook.c:640: Async hook execution via system(full_cmd) — executes user-defined scripts
scorpiox-wsl.c:876: Complex chroot+overlay command string built with user-provided args
3.4 What Processes Are Spawned
| Spawned Process | Spawning Source | Purpose |
|---|
Container child (container_main) | scorpiox-unshare.c | Isolated container root process |
bash / sh | scorpiox-bash.c, scorpiox-init.c, sx_exec.c | Command execution |
python3 | scorpiox-server.c, scorpiox-traffic.c | CGI script execution, MITM proxy |
slirp4netns | scorpiox-unshare.c | User-space network stack for containers |
newuidmap / newgidmap | scorpiox-unshare.c | UID/GID mapping for unprivileged containers |
ssh / scp | scorpiox-sshpass.c | Remote command execution |
git | scorpiox-agent.c, scorpiox-mirror-git.c | Repository operations |
tmux | scorpiox-tmux.c, sxtmux_backend_tmux.c | Terminal multiplexing |
scorpiox-whatsapp-bridge | scorpiox-whatsapp.c | WhatsApp integration bridge |
wsl.exe | scorpiox-wsl.c | WSL distro management |
ip | scorpiox-unshare.c | Network interface configuration (inside container) |
apk / apt-get / pacman | scorpiox-unshare.c | Package installation inside container |
vim / vi / nano | sx.c | User text editing |
sox (rec) | scorpiox-voice.c | Audio recording for voice input |
4. Filesystem Access Scope
4.1 Primary Data Directories
| Path | Access Mode | Purpose |
|---|
~/.scorpiox/ | Read/Write | Primary config, sessions, conversations, traffics, hooks, agents |
.scorpiox/ (CWD-relative) | Read/Write | Project-level sessions, hooks, conversations |
SCORPIOX_HOME (env override) | Read/Write | User-configurable base directory |
4.2 System Paths Accessed
| Path | Component | Access | Purpose |
|---|
/proc/self/exe | scorpiox-unshare | Read | Find own binary path for container bind-mount |
/proc//uid_map, /proc//gid_map | scorpiox-unshare | Write | User namespace UID/GID mapping |
/proc//setgroups | scorpiox-unshare | Write | Allow setgroups in namespace |
/etc/subuid, /etc/subgid | scorpiox-unshare | Read/Write | Subordinate UID/GID ranges; auto-creates entries when root |
/sys/fs/cgroup/sx-/ | scorpiox-unshare | Create/Write | Memory cgroup for containers |
/dev/kvm | scorpiox-vm | Read/Write | KVM virtualization |
/dev/net/tun | scorpiox-vm | Read/Write | TUN/TAP networking for VMs |
/dev/bpf | scorpiox-thunderbolt4 | Read/Write | Berkeley Packet Filter for raw Ethernet |
/dev/null, /dev/zero, /dev/random, /dev/urandom, /dev/tty, /dev/pts/ | scorpiox-unshare | Bind-mount | Standard device nodes inside container |
/tmp/sxmux/ | sxmux_session | Create/Read/Write | Multiplexer Unix sockets and PID files |
/tmp/sx_ | Multiple | Create/Write | Temporary files for voice, emit, proxy |
/tmp/scorpiox-server/ | scorpiox-server | Create/Write | Git deploy cache |
/var/mail/ | sxmail_ | Read/Write | Maildir storage for email server |
4.3 Container Filesystem Scope (scorpiox-unshare)
Inside the container, the process creates a complete isolated rootfs:
- Root filesystem: overlayfs (preferred) or bind-mount of extracted
.tar image
/proc: Fresh procfs mount (within user namespace)
/sys: Read-only sysfs mount
/dev: tmpfs with bind-mounted device nodes from host
/dev/pts: Fresh devpts instance
/dev/shm: tmpfs
/tmp, /run: Fresh tmpfs mounts
/opt/host-bin: Read-only bind-mount of host scorpiox binaries
- User bind-mounts:
--bind and -v options for host directory sharing
5. System Call Analysis
5.1 Namespace & Container Syscalls
| Syscall | File | Context |
|---|
clone() with CLONE_NEWNS\ | CLONE_NEWPID\ | CLONE_NEWUTS\ | CLONE_NEWUSER\ | CLONE_NEWNET | scorpiox-unshare.c:1831 | Container creation |
unshare(CLONE_NEWUSER) | scorpiox-unshare.c:645 | User namespace probe |
SYS_pivot_root | scorpiox-unshare.c:1489 | Switch container root filesystem |
sethostname() | scorpiox-unshare.c:1337 | Set container hostname |
mount() (12+ call sites) | scorpiox-unshare.c | proc, sysfs, tmpfs, overlayfs, bind mounts |
umount2() with MNT_DETACH | scorpiox-unshare.c:1501 | Detach old root after pivot |
5.2 KVM Virtualization Syscalls
| Syscall | File | Context |
|---|
ioctl(KVM_CREATE_VM) | scorpiox-vm.c:2018 | Create virtual machine |
ioctl(KVM_CREATE_VCPU) | scorpiox-vm.c:2093 | Create virtual CPU |
ioctl(KVM_SET_USER_MEMORY_REGION) | scorpiox-vm.c:2052 | Map guest memory |
ioctl(KVM_SET_SREGS/REGS) | scorpiox-vm.c:2440+ | Configure CPU registers |
ioctl(KVM_RUN) | scorpiox-vm.c (vCPU loop) | Execute guest code |
ioctl(KVM_IRQ_LINE) | scorpiox-vm.c:914+ | Inject interrupts |
ioctl(TUNSETIFF) | scorpiox-vm.c:1669 | TUN/TAP network interface |
5.3 Memory Mapping
| Call | File | Flags | Purpose |
|---|
mmap() | scorpiox-vm.c:2035 | PROT_READ\ | PROT_WRITE, MAP_PRIVATE\ | MAP_ANONYMOUS\ | MAP_NORESERVE | Guest VM memory (up to GBs) |
mmap() | scorpiox-vm.c:2105 | PROT_READ\ | PROT_WRITE, MAP_SHARED | vCPU run structure |
mmap() | scorpiox-vm.c:2848 | PROT_READ\ | PROT_WRITE, MAP_PRIVATE\ | MAP_ANONYMOUS | BIOS ROM buffer |
No PROT_EXEC mappings exist anywhere in the codebase. No
mprotect() calls. No JIT or self-modifying code. This is a strong security positive.
5.4 Signal Handling
Standard signal handling patterns used across the codebase:
SIGINT/SIGTERM/SIGHUP: Cleanup handlers in scorpiox-unshare, scorpiox-wsl, scorpiox-traffic, scorpiox-whatsapp, scorpiox-vm, scorpiox-thunderbolt4
SIGCHLD: SIG_IGN for auto-reaping children (sxmux_session)
SIGPIPE: SIG_IGN for network robustness (multiple components)
SIGWINCH: Terminal resize handling (sx_term.c, scorpiox-vi.c)
SIGILL: CPU feature detection in mbedTLS (vendor code only)
5.5 Other Notable Syscalls
| Call | Context |
|---|
setsid() | Daemon mode in scorpiox-dns, scorpiox-init (service launcher), sxmux_session |
chdir() | CGI script execution in scorpiox-server, daemon mode |
readlink("/proc/self/exe") | Self-location for container binary bind-mounting |
sethostname() | Container hostname isolation |
6. Sandboxing / Isolation Model
6.1 Container Isolation (scorpiox-unshare)
scorpiox-unshare implements a comprehensive Linux container runtime with multi-layer isolation:
| Layer | Implementation | Assessment |
|---|
| User Namespace | CLONE_NEWUSER — maps host UID to container root (UID 0) | ✅ Strong — unprivileged by default |
| Mount Namespace | CLONE_NEWNS + MS_REC\ | MS_PRIVATE — prevents mount propagation to host | ✅ Strong |
| PID Namespace | CLONE_NEWPID — container gets PID 1 | ✅ Strong |
| UTS Namespace | CLONE_NEWUTS — isolated hostname | ✅ Strong |
| Network Namespace | CLONE_NEWNET + slirp4netns — isolated network with user-space NAT; --net host opt-out | ✅ Strong (default isolated) |
| Filesystem | pivot_root + overlayfs/bind-mount — complete rootfs change | ✅ Strong |
| Device Isolation | tmpfs /dev with minimal bind-mounted nodes | ✅ Good |
| Memory Limits | cgroup v2 memory.max via --memory flag | ✅ Good (optional) |
| Port Forwarding | Explicit -p port mapping with range parsing | ✅ Controlled |
6.2 Isolation Gaps
| Gap | Description | Risk |
|---|
--privileged mode | Skips user namespace entirely, runs as real root inside container | 🔴 High — but requires explicit flag AND running as root |
--net host | Shares host network namespace | ⚠️ Medium — explicit opt-in |
| No seccomp filter | Container processes have access to all syscalls allowed by user namespace | ⚠️ Medium — user namespaces restrict most dangerous calls, but a seccomp profile would add defense-in-depth |
| No AppArmor/SELinux profiles | No mandatory access control confinement | ⚠️ Medium |
| Bind-mount permissions | User-provided --bind and -v mounts share host directories with full container access | ⚠️ Medium — expected behavior, but user must be careful |
| No capability dropping | No capset() or prctl(PR_SET_NO_NEW_PRIVS) — relies entirely on user namespace restrictions | ⚠️ Low — user namespaces effectively limit capabilities |
6.3 VM Isolation (scorpiox-vm)
KVM-based VMs provide hardware-level isolation:
- Full CPU/memory/device separation via KVM
- Separate guest memory region (
mmap + KVM_SET_USER_MEMORY_REGION)
- Optional TUN/TAP networking with bridge support
- Shared directories via 9p/virtio or custom initramfs injection
6.4 WSL Isolation (scorpiox-wsl)
Windows-specific: uses WSL's built-in isolation + overlayfs chroot within WSL for additional filesystem isolation.
7. IPC Mechanisms
| Mechanism | Component(s) | Purpose |
|---|
Unix Domain Sockets (AF_UNIX, SOCK_STREAM) | sxmux_session.c | Terminal multiplexer client-server communication; sockets at /tmp/sxmux/ |
Named Pipes (Windows CreateNamedPipe) | sxmux_session.c (Windows path) | Same purpose on Windows: \\.\pipe\sxmux- |
Anonymous Pipes (pipe()) | scorpiox-unshare.c (sync_pipe, net_pipe), scorpiox-bash.c, scorpiox-whatsapp.c, sx_exec.c | Parent-child synchronization, command output capture |
Signals (kill(), SIGTERM, SIGINT) | Multiple | Process lifecycle management, cleanup coordination |
TCP Sockets (AF_INET) | sxmail_smtp.c, sxmail_imap.c, scorpiox-server.c, scorpiox-server-http2tcp.c, scorpiox-dns.c | Network services (SMTP, IMAP, HTTP, DNS) |
| stdout/stdin | sx_exec.c, scorpiox-bash.c | Captured command output, streaming |
| Environment Variables | Multiple | Configuration passing between parent/child processes |
| PID Files | sxmux_session.c | Session liveness detection at /tmp/sxmux/ |
No shared memory (shm_open, shmget) or message queues (mqueue) are used.
8. Environment Modification Analysis
8.1 Standard Environment Setting
These are benign, expected modifications within container/child contexts:
| Variable | Component | Context |
|---|
PATH | scorpiox-unshare.c | Standard path inside container |
HOME, USER, TERM, LANG | scorpiox-unshare.c | Container environment setup |
container=scorpiox-unshare | scorpiox-unshare.c | Container detection hint |
SXMUX_INIT_CMD | sxmux_session.c | Multiplexer initial command |
REQUEST_METHOD, CONTENT_TYPE, etc. | scorpiox-server.c | CGI environment variables |
8.2 Security-Sensitive Environment Modifications
| Variable(s) | Component | Risk |
|---|
HTTP_PROXY, HTTPS_PROXY, http_proxy, https_proxy | scorpiox-traffic.c:942-945 | 🔴 High — redirects all HTTP(S) traffic through MITM proxy |
NODE_TLS_REJECT_UNAUTHORIZED=0 | scorpiox-traffic.c:975 | 🔴 High — disables TLS certificate verification for Node.js |
REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE, SSL_CERT_FILE | scorpiox-traffic.c:976-978 | 🔴 High — overrides CA bundle to custom cert for MITM |
PYTHONHTTPSVERIFY=0 | scorpiox-traffic.c:979 | 🔴 High — disables Python HTTPS verification |
CURLOPT_SSL_VERIFYPEER=0 | scorpiox-traffic.c:980 | 🔴 High — disables curl peer verification |
Mitigating context: These modifications are
intentional —
scorpiox-traffic is explicitly a traffic capture/MITM tool. The environment changes are applied only to the child process being monitored (
fork() +
execvp() at line 984), not globally. However, the tool's purpose inherently requires weakening TLS security for the wrapped process.
8.3 No LD_PRELOAD / LD_LIBRARY_PATH Modification
The codebase does not modify LD_PRELOAD or LD_LIBRARY_PATH anywhere. No dynamic library injection vectors exist.
9. Principle of Least Privilege Assessment
9.1 Strengths
| Area | Assessment |
|---|
| No privilege escalation | Zero setuid/setgid/seteuid/setegid calls in entire codebase |
| Rootless containers by default | scorpiox-unshare uses user namespaces — no root needed |
| No executable memory | No PROT_EXEC mmap, no mprotect, no JIT — strong W^X compliance |
| Explicit root checks | scorpiox-thunderbolt4 explicitly checks geteuid() == 0 before proceeding |
| Process monitoring | sx_procmon.c tracks fork/pipe/FD counts for leak detection |
| No shared memory | No shm_open/shmget reduces inter-process attack surface |
| Read-only host bind | Host scorpiox binaries are bind-mounted read-only into containers |
9.2 Weaknesses
| Area | Issue | Recommendation |
|---|
Excessive system() usage | 31+ call sites using shell command execution; command injection risk if inputs aren't sanitized | Replace system() with direct fork()+exec() where possible; validate/escape inputs |
| No seccomp in containers | Container child processes can invoke any syscall allowed by user namespace | Add seccomp(SCMP_ACT_ERRNO) filter to restrict container syscalls to known-needed set |
No PR_SET_NO_NEW_PRIVS | Container children could theoretically gain privileges via setuid binaries inside rootfs | Call prctl(PR_SET_NO_NEW_PRIVS, 1) in container_main before exec |
/etc/subuid auto-creation | When running as root, auto-appends to /etc/subuid and /etc/subgid without locking | Use atomic file operations or lock files |
| Temp file predictability | Uses predictable paths like /tmp/sx_voice.wav, /tmp/.sx-unshare-list.html, /tmp/sx_emit_* | Use mkstemp() or mkdtemp() for temp files |
| CGI fork model | scorpiox-server forks per-request for CGI execution; no resource limits on spawned children | Add per-child timeouts and process count limits |
scorpiox-sshpass design | Deliberately disables all SSH host key checking (StrictHostKeyChecking=no, UserKnownHostsFile=/dev/null) | Acceptable for stated "home lab only" purpose, but should include runtime warnings |
| DNS on port 53 | scorpiox-dns defaults to port 53 without capability-based port binding | Use CAP_NET_BIND_SERVICE capability instead of full root |
10. Risk Assessment
10.1 Risk Matrix
| Risk | Severity | Likelihood | Components | Mitigation |
|---|
Command injection via system() | High | Medium | scorpiox-unshare, scorpiox-agent, scorpiox-hook, scorpiox-wsl | Sanitize inputs; prefer exec*() |
| Container escape | Critical | Low | scorpiox-unshare | User namespaces + pivot_root provide strong isolation; add seccomp |
| TLS bypass in traffic capture | High | High (by design) | scorpiox-traffic | Document clearly; scope env changes to child only ✅ |
| Temp file race conditions (symlink attacks) | Medium | Low | Multiple tools | Use mkstemp(); set restrictive umask |
| KVM guest-to-host escape | Critical | Very Low | scorpiox-vm | Hardware-enforced KVM isolation; keep kernel patched |
| Privileged port binding without dropping privileges | Medium | Medium | scorpiox-dns, sxmail_smtp | Bind port then drop privileges; use capabilities |
| Unbounded CGI process spawning | Medium | Medium | scorpiox-server | Add connection limits and child process caps |
| BPF raw network access | High | Low | scorpiox-thunderbolt4 | Root requirement is enforced ✅ |
--privileged container flag | High | Low | scorpiox-unshare | Requires both flag AND root — double gate ✅ |
| Predictable Unix socket paths | Low | Low | sxmux_session at /tmp/sxmux/ | Check socket ownership; use per-user subdirs |
10.2 Overall Assessment
The ScorpioX codebase demonstrates a generally sound security architecture for a systems-level toolkit:
- Container isolation (
scorpiox-unshare) follows industry-standard patterns (matching Docker/Podman rootless) with user namespaces, mount isolation, PID isolation, network isolation, and filesystem isolation via pivot_root.
- No privilege escalation is attempted anywhere — the code never calls setuid/setgid/prctl for privilege gain.
- Memory safety is enhanced by the absence of executable memory mappings (no JIT, no W^X violations).
- The main risks center on the extensive use of
system() for shell command execution (command injection surface) and the absence of seccomp filtering in containers.
Overall Risk Rating: MEDIUM — The codebase is well-structured with clear separation of privileged operations, but would benefit from replacing
system() calls with direct exec, adding seccomp filters to containers, and using secure temporary file creation patterns.
Report generated by Security Audit Agent on 2026-04-28