# Security Audit: OS-Level Permissions, System Access & Sandboxing

**Audit Date:** 2026-04-28  
**Codebase:** ScorpioX Clang  
**Scope:** Process spawning, privilege model, filesystem access, sandboxing, IPC mechanisms  
**Files Analyzed:** 493 C/H files (88 core `.c` files, ~60,000 LOC non-vendor)

---

## 1. Executive Summary

The ScorpioX codebase is a **multi-tool platform** encompassing a TUI chat client, container runtime, VM hypervisor, web server, mail server, traffic interceptor, and numerous utility programs. The permission model varies dramatically by component:

| Risk Level | Component | Reason |
|:---:|---|---|
| 🔴 **CRITICAL** | `scorpiox-traffic` | Disables TLS verification globally for child processes |
| 🔴 **CRITICAL** | `scorpiox-sshpass` | Disables all SSH host key checking by design |
| 🟠 **HIGH** | `scorpiox-unshare` | Container runtime with `--privileged` mode bypassing user namespaces |
| 🟠 **HIGH** | `scorpiox-vm` | Direct KVM access via `/dev/kvm` ioctls, mmap of guest memory |
| 🟠 **HIGH** | `scorpiox-server` | Fork-per-request model executing arbitrary Python scripts via `execlp` |
| 🟠 **HIGH** | `scorpiox-thunderbolt4` | Requires root for raw BPF Ethernet frame access |
| 🟡 **MEDIUM** | `sx.c` (main TUI) | Extensive `system()`/`popen()` calls for subcommand dispatch |
| 🟡 **MEDIUM** | `sxmux_session` | Daemon fork with Unix domain sockets in `/tmp/sxmux` |
| 🟢 **LOW** | `scorpiox-podman` | Thin wrapper delegating to Podman; no direct privilege use |

---

## 2. Privilege Requirements

### 2.1 Components Requiring Root/Elevated Privileges

| Component | Privilege Required | Reason |
|---|---|---|
| `scorpiox-thunderbolt4` | **Root (sudo)** | Opens `/dev/bpf*` for raw Ethernet frames (line 1410: `geteuid() != 0` check) |
| `scorpiox-unshare --privileged` | **Root** | Skips user namespace, runs container as real root (line 2182: `getuid() != 0` check) |
| `scorpiox-vm` | **`kvm` group** | Opens `/dev/kvm` (O_RDWR) for hardware virtualization (line 1997) |
| `scorpiox-unshare` (cgroup memory) | **Root or cgroup2 delegation** | Creates cgroup dirs at `/sys/fs/cgroup/sx-<pid>/` (line 881) |

### 2.2 Components Running as Unprivileged User

The majority of tools run as the invoking user:

- **`sx.c`** (main TUI) — no privilege escalation
- **`scorpiox-bash`** — shell command executor, inherits caller privileges
- **`scorpiox-server`** — HTTP server binding to user ports (>1024 by default)
- **`scorpiox-agent`** — git clone + dotnet build + launch
- **`scorpiox-unshare`** (default) — uses **user namespaces** for rootless containers
- All mail components (`sxmail_*`) — user-level mail handling

### 2.3 No `setuid`/`setgid` Binary Installation

The codebase does **not** install setuid binaries. It references external setuid helpers:
- `/usr/bin/newuidmap` and `/usr/bin/newgidmap` (system-provided, line 775-776 in `scorpiox-unshare.c`) for full UID/GID range mapping in user namespaces.

**Finding:** ✅ No self-installed setuid binaries. ⚠️ Relies on system setuid helpers for container UID mapping.

---

## 3. Process Spawning Inventory

### 3.1 Quantitative Summary (non-vendor code)

| Mechanism | Count | Risk Level |
|---|:---:|:---:|
| `system()` | 107 | 🟠 HIGH — shell injection surface |
| `exec*()` family | 66 | 🟡 MEDIUM — direct exec |
| `popen()` | 61 | 🟠 HIGH — shell-mediated pipe |
| `fork()` | 47 | 🟡 MEDIUM — process isolation |
| `CreateProcessA()` (Windows) | 40 | 🟡 MEDIUM |
| `clone()` (Linux namespaces) | 1 | 🟠 HIGH — namespace creation |

### 3.2 Critical Process Spawning Patterns

#### 3.2.1 `system()` — Shell Command Injection Surface

The most pervasive pattern. Many `system()` calls construct commands with `snprintf()`:

**sx.c** (main TUI):
- Line 763: `system(transcript_cmd)` — transcript generation
- Line 1332: `system(cmd)` — configuration commands
- Line 1589: `system(cmd)` — subcommand dispatch
- Line 2123: `system(config_cmd)` — config operations
- Line 2276: `system(rewind_cmd)` — rewind operations
- Line 2472: `system(voice_cmd)` — voice commands

**sxtmux_backend_tmux.c**: Lines 91, 97, 138, 144 — tmux session management via `system()`

**sxmail_maildir.c**: Lines 704, 711 — mail directory operations

**scorpiox-unshare.c**: Line 1581 — `system("ip link set lo up 2>/dev/null")` inside container (low risk — isolated namespace)

**Risk:** `system()` invokes `/bin/sh -c` and is vulnerable to shell metacharacter injection if any argument is user-controlled. While most calls use `snprintf()` with controlled formats, the attack surface is broad.

**Positive Note:** `sx.c` line 662 explicitly uses `fork()+execlp()` for the editor launch "to avoid shell metacharacter injection" — demonstrating awareness of the issue, though this pattern is not consistently applied.

#### 3.2.2 `popen()` — Shell-Mediated Pipe Reads

- `sx.c` lines 1202-1204: `popen("git rev-parse --abbrev-ref HEAD ...")` — git branch detection
- `sxtmux_backend_tmux.c` line 42: `popen("tmux list-sessions ...")` — tmux enumeration
- `sxtmux_backend_sxmux.c` line 140: `popen("which tmux 2>/dev/null")` — tmux detection
- Numerous occurrences across the codebase for tool detection and status queries

#### 3.2.3 `clone()` with Namespace Flags

**scorpiox-unshare.c** line 1831:
```c
int clone_flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD;
if (!skip_userns)
    clone_flags |= CLONE_NEWUSER;
if (use_netns)
    clone_flags |= CLONE_NEWNET;
pid_t child = clone(container_main, stack_top, clone_flags, &cfg);
```

Namespaces created:
- **Mount namespace** (`CLONE_NEWNS`) — always
- **PID namespace** (`CLONE_NEWPID`) — always
- **UTS namespace** (`CLONE_NEWUTS`) — always
- **User namespace** (`CLONE_NEWUSER`) — unless running as root
- **Network namespace** (`CLONE_NEWNET`) — unless `--net host`

**Missing:** `CLONE_NEWIPC` is **not** used — IPC namespace is shared with host.

#### 3.2.4 `fork()` + `exec*()` Patterns

- **scorpiox-server.c** line 2805: Fork-per-request HTTP server (`fork()` → `handle_request()` → `execlp("python3", ...)`)
- **sxtmux_backend_sxmux.c** line 86: `fork()` + `execlp("scorpiox-multiplexer", ...)`
- **sxmux_session.c** line 1601: Daemon fork for multiplexer session
- **scorpiox-traffic.c** line 933: `fork()` + `execvp()` for proxied command execution

#### 3.2.5 `CreateProcessA()` (Windows)

- **scorpiox-wsl.c** lines 252, 306: Self-relaunch for admin/elevation
- **sxmux_session.c** line 1941: Daemon process creation
- **scorpiox-bash.c**: Shell command execution via pipe-connected child

---

## 4. Filesystem Access Scope

### 4.1 Directories Accessed

| Path Pattern | Component | Access Type |
|---|---|---|
| `~/.scorpiox/` | All tools | R/W — config, sessions, conversations, logs |
| `.scorpiox/` (CWD-relative) | `sx.c`, agents | R/W — sessions, hooks, skills |
| `/tmp/sxmux/` | `sxmux_session` | R/W — Unix socket dir, PID files |
| `/tmp/sx_*` | Various | R/W — temporary files (voice, emit, slirp sockets) |
| `/proc/<pid>/uid_map`, `gid_map`, `setgroups` | `scorpiox-unshare` | W — user namespace setup |
| `/sys/fs/cgroup/sx-<pid>/` | `scorpiox-unshare` | R/W — memory cgroup |
| `/etc/subuid`, `/etc/subgid` | `scorpiox-unshare` | R (W if root) — UID mapping |
| `/dev/kvm` | `scorpiox-vm` | R/W — KVM hypervisor |
| `/dev/net/tun` | `scorpiox-vm` | R/W — TAP networking |
| `/dev/bpf*` | `scorpiox-thunderbolt4` | R/W — raw Ethernet |
| `/var/mail/` | `sxmail_*` | R/W — mail storage |
| `/usr/lib/scorpiox/vmlinuz` | `scorpiox-vm` | R — default kernel |
| `/opt/scorpiox-agent/` | `scorpiox-agent` | R/W — agent cache |

### 4.2 Container Filesystem Mounts

Inside `scorpiox-unshare`, the container child sets up an extensive filesystem:

| Mount | Type | Flags |
|---|---|---|
| `/` (root) | MS_REC \| MS_PRIVATE | Prevents mount propagation to host |
| rootfs | overlayfs or bind | `MS_NODEV` on overlay |
| `/dev` | tmpfs | `MS_NOSUID` |
| `/dev/pts` | devpts | `MS_NOSUID \| MS_NOEXEC` |
| `/dev/shm` | tmpfs | `MS_NOSUID \| MS_NODEV` |
| `/proc` | procfs | `MS_NOSUID \| MS_NODEV \| MS_NOEXEC` |
| `/sys` | sysfs | `MS_NOSUID \| MS_NODEV \| MS_NOEXEC \| MS_RDONLY` |
| `/tmp` | tmpfs | `MS_NOSUID \| MS_NODEV` |
| `/run` | tmpfs | `MS_NOSUID \| MS_NODEV` |
| `/workspace` | bind (host dir) | Optional: `--bind` flag |
| `/persist` | bind (host dir) | Optional: `--persist` flag |
| `/opt/host-bin` | bind (host exe dir) | Read-only (host binaries) |
| GPU devices | bind | Optional: `--gpu` flag |

**Positive:** Mount flags consistently use `MS_NOSUID`, `MS_NODEV`, and `MS_NOEXEC` where appropriate.

### 4.3 Filesystem Access Concerns

1. **Broad `/tmp` usage**: Multiple tools create world-readable files in `/tmp` (`/tmp/sx_*`, `/tmp/.sx-unshare-list.html`, `/tmp/sxmux/`). This is a **symlink attack surface** on multi-user systems.

2. **Host binary auto-mount**: `scorpiox-unshare` automatically bind-mounts the host's `scorpiox` binary directory into containers at `/opt/host-bin` (read-only). While read-only, this exposes the host binary layout.

3. **GPU passthrough**: When `--gpu` is used, NVIDIA device nodes (`/dev/nvidia*`, `/dev/dri/*`) are bind-mounted into the container, expanding the attack surface.

---

## 5. System Call Analysis

### 5.1 KVM ioctls (scorpiox-vm.c)

The VM module performs extensive KVM operations:

| ioctl | Purpose | Line |
|---|---|---|
| `KVM_GET_API_VERSION` | API compatibility check | 2007 |
| `KVM_CREATE_VM` | Create VM instance | 2021 |
| `KVM_SET_TSS_ADDR` | TSS configuration | 2027 |
| `KVM_CREATE_IRQCHIP` | Interrupt controller | 2030 |
| `KVM_CREATE_PIT2` | Timer (PIT) | 2034 |
| `KVM_SET_USER_MEMORY_REGION` | Map guest memory (×3) | 2055, 2067, 2085 |
| `KVM_CREATE_VCPU` | Create virtual CPU | 2096 |
| `KVM_GET_VCPU_MMAP_SIZE` | vCPU run struct size | 2102 |
| `KVM_GET_SUPPORTED_CPUID` | CPU feature detection | 2123 |
| `KVM_SET_CPUID2` | Set guest CPUID | 2144 |
| `KVM_GET_SREGS`/`KVM_SET_SREGS` | Segment registers | 2384, 2443 |
| `KVM_SET_REGS` | General-purpose registers | 2455 |
| `KVM_IRQ_LINE` | Inject interrupts | 917, 1463, 1538, 1897, 1969 |

### 5.2 mmap Usage (scorpiox-vm.c)

```c
// Line 2038: Guest memory allocation - RW, no exec
g_guest_mem = mmap(NULL, g_guest_mem_size, PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);

// Line 2108: KVM run struct mapping
g_kvm_run = mmap(NULL, (size_t)mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_vcpu_fd, 0);
```

**Positive:** Guest memory is mapped as `PROT_READ | PROT_WRITE` without `PROT_EXEC` — no executable host pages.

### 5.3 TUN/TAP ioctls (scorpiox-vm.c)

```c
// Line 1662: Open TUN device
int fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
// Line 1672: Configure TAP interface
ioctl(fd, TUNSETIFF, &ifr);
// Lines 1687-1703: Network interface configuration
ioctl(sock, SIOCGIFFLAGS, &ifr_up);
ioctl(sock, SIOCSIFFLAGS, &ifr_up);
ioctl(sock, SIOCBRADDIF, &ifr_br);
```

### 5.4 BPF ioctls (scorpiox-thunderbolt4.c — macOS only)

Opens `/dev/bpf*` devices for raw Ethernet frame transmission — requires root.

### 5.5 Signal Handling

- **`scorpiox-server.c`**: `SIGCHLD` handler for reaping forked children (line 2800)
- **`scorpiox-vm.c`**: Signal handlers for clean VM shutdown
- **`scorpiox-unshare.c`**: Parent catches signals to forward to container child
- **mbedtls (vendor)**: `SIGILL` handler for CPU feature detection (SHA256/SHA512)
- **mbedtls (vendor)**: `SIGPIPE` set to `SIG_IGN` for network sockets

---

## 6. Sandboxing / Isolation Model

### 6.1 `scorpiox-unshare` — Linux Container Runtime

**Architecture:** Rootless container using Linux user namespaces.

#### Namespace Isolation

| Namespace | Used | Notes |
|---|:---:|---|
| User (`CLONE_NEWUSER`) | ✅ | Skipped when running as root |
| Mount (`CLONE_NEWNS`) | ✅ | Always — private mount tree |
| PID (`CLONE_NEWPID`) | ✅ | Always — isolated PID space |
| UTS (`CLONE_NEWUTS`) | ✅ | Always — custom hostname |
| Network (`CLONE_NEWNET`) | ✅ | Default; `--net host` disables |
| IPC | ❌ | **Not isolated — shares host IPC** |
| Cgroup | ❌ | **Not isolated — v2 memory limits only** |

#### Rootfs Isolation
- **Overlayfs** (kernel ≥5.11): Copy-on-write layer over read-only rootfs
- **Bind mount fallback**: Direct bind for older kernels
- `MS_REC | MS_PRIVATE` on root prevents mount propagation to host

#### Network Isolation
- Default: `CLONE_NEWNET` + **slirp4netns** for userspace networking
- Port mapping via slirp4netns API (`add_hostfwd` command)
- `--net host` bypasses all network isolation

#### Resource Limits
- Optional `--memory` flag: cgroup v2 `memory.max` enforcement
- No CPU, PID count, or I/O bandwidth limits

#### Environment Sanitization
- `clearenv()` wipes inherited environment (line 1546)
- Sets minimal, controlled `PATH`, `HOME`, `TERM`, `LANG`, `USER`
- Passes through `SCORPIOX_BRANCH`, `CONTAINER_PACKAGES` explicitly
- User-specified `-e KEY=VALUE` vars applied after sanitization

### 6.2 `scorpiox-vm` — KVM Virtual Machine

**Architecture:** Full hardware-level isolation via KVM.

- Guest runs in its own address space (mmap'd memory region)
- vCPU confined by KVM (hardware-enforced ring separation)
- Serial console I/O only (no shared filesystem by default)
- TAP networking with optional bridge attachment
- `/dev/kvm` access required — enforced by kernel

### 6.3 `scorpiox-wsl` — WSL2 Execution

**Architecture:** Delegates to Windows WSL2 infrastructure.

- Uses `wsl.exe --distribution` for execution
- Overlayfs chroot inside WSL for stateless operation (line 838: `chroot $OV/merged /bin/sh -c '...'`)
- Windows-side isolation managed by Hyper-V (WSL2 is a VM)

### 6.4 `scorpiox-podman` — Podman Wrapper

**Architecture:** Thin CLI wrapper delegating to Podman.

- Constructs `podman run` command and calls `system(cmd)`
- All isolation provided by Podman/OCI runtime
- No direct namespace or privilege management

### 6.5 Sandboxing Gaps

| Gap | Impact | Recommendation |
|---|---|---|
| No IPC namespace in `scorpiox-unshare` | Container can access host System V IPC (shared memory, semaphores, message queues) | Add `CLONE_NEWIPC` to clone flags |
| No cgroup namespace isolation | Container can see host cgroup hierarchy | Add `CLONE_NEWCGROUP` |
| No seccomp filter | Container processes can invoke all syscalls | Apply seccomp-bpf filter for container child |
| No capability dropping | Root-in-userns retains all user-namespace capabilities | Drop unnecessary capabilities with `prctl(PR_SET_KEEPCAPS)` + `capset()` |
| `/proc/sys/kernel/random` synthetic mount | Only provides static file contents (uuid, boot_id) — not cryptographically valid | Document limitation; consider bind-mounting from host |

---

## 7. IPC Mechanisms

### 7.1 Unix Domain Sockets

**sxmux_session.c**: Terminal multiplexer daemon communication.
- Socket directory: `/tmp/sxmux/` (defined in `sxmux_session.h` line 26)
- Pattern: `AF_UNIX`, `SOCK_STREAM` (lines 1573, 1718)
- Server: `bind()` + `listen()` + `accept()` loop
- Client: `connect()` to named socket
- Protocol: Length-prefixed messages with type codes (SXMUX_MSG_INPUT, SXMUX_MSG_OUTPUT, SXMUX_MSG_RESIZE, SXMUX_MSG_SENDKEYS)

**Security concern:** Socket created in `/tmp/sxmux/` with standard permissions. On multi-user systems, another user could potentially connect.

### 7.2 Named Pipes (Windows)

**sxmux_session.c** (Windows path):
- Pipe name pattern: `\\.\pipe\sxmux-<name>` (line 22)
- Created with `CreateNamedPipeA()` (line 1976)
- Client connects via `CreateFileA()` + `WaitNamedPipeA()`

### 7.3 Pipes (Anonymous)

Used extensively for parent-child communication:

| Component | Purpose |
|---|---|
| `scorpiox-unshare.c` | `sync_pipe` — UID map readiness signal (line 1787) |
| `scorpiox-unshare.c` | `net_pipe` — network namespace readiness (line 1805) |
| `scorpiox-server.c` | `stdin_pipe`/`stdout_pipe` — CGI I/O (line 1660) |
| `scorpiox-bash.c` | stdin/stdout/stderr pipes to child shell |

### 7.4 PTY (Pseudo-Terminal)

**sxmux_pane.c**: Each terminal pane uses `forkpty()` / manual PTY allocation for full terminal emulation.

### 7.5 Signals

- `SIGCHLD` — child reaping in server and container parent
- `SIGPIPE` — ignored in network code (mbedtls, server)
- `SIGILL` — CPU feature probing (mbedtls SHA)
- Various termination signals forwarded from container parent to child

---

## 8. Environment Variable Modification

### 8.1 Security-Sensitive Environment Changes

#### 🔴 CRITICAL: TLS Verification Bypass (`scorpiox-traffic.c`)

Lines 975-980 in child process before `execvp()`:
```c
setenv("NODE_TLS_REJECT_UNAUTHORIZED", "0", 1);
setenv("REQUESTS_CA_BUNDLE", custom_ca_path, 1);
setenv("CURL_CA_BUNDLE", custom_ca_path, 1);
setenv("SSL_CERT_FILE", custom_ca_path, 1);
setenv("PYTHONHTTPSVERIFY", "0", 1);
setenv("CURLOPT_SSL_VERIFYPEER", "0", 1);
```

Also sets `HTTP_PROXY`/`HTTPS_PROXY` to local MITM proxy (lines 942-945).

**Impact:** Any child process launched by `scorpiox-traffic` has TLS verification completely disabled. This is by design (traffic inspection tool), but represents a significant security boundary.

#### 🟠 HIGH: Proxy Environment (`scorpiox-traffic.c`)

Lines 942-945: Sets `HTTP_PROXY`, `HTTPS_PROXY`, `http_proxy`, `https_proxy` to local MITM proxy endpoint.

#### 🟡 MEDIUM: Container Environment Reset (`scorpiox-unshare.c`)

Lines 1546-1554: `clearenv()` followed by controlled `setenv()`:
```c
clearenv();
setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
setenv("HOME", "/root", 1);
// ... controlled vars only
```

**Positive:** This is a security-positive pattern — sanitizes inherited environment.

#### 🟡 MEDIUM: CGI Environment Injection (`scorpiox-server.c`)

Lines 1692-1725: Sets CGI standard environment variables from HTTP request data:
```c
setenv("REQUEST_METHOD", req->method, 1);
setenv("CONTENT_TYPE", req->content_type, 1);
setenv("HTTP_COOKIE", req->cookie, 1);
setenv("QUERY_STRING", req->query, 1);
setenv("HTTP_AUTHORIZATION", req->authorization, 1);
```

Also line 1504: All HTTP headers mapped to `HTTP_*` environment variables via `set_cgi_header_envs()`.

**Risk:** Standard CGI practice, but authorization tokens are placed in environment variables visible to child processes.

### 8.2 Non-Security Environment Changes

- `SXMUX_INIT_CMD` — multiplexer session init command (temporary, unset after use)
- `TRAFFIC_OUTDIR`, `TRAFFIC_PORT` — traffic capture config
- `VNC_PORT` — container VNC port

---

## 9. Principle of Least Privilege Assessment

### 9.1 Positive Patterns

| Pattern | Location | Assessment |
|---|---|---|
| User namespaces for rootless containers | `scorpiox-unshare.c` | ✅ Excellent — no root needed for basic containers |
| `O_CLOEXEC` on sensitive file descriptors | `scorpiox-vm.c` (KVM, TUN) | ✅ Good — prevents FD leaks to children |
| `MS_NOSUID | MS_NODEV | MS_NOEXEC` mount flags | `scorpiox-unshare.c` | ✅ Good — restricts container mount capabilities |
| `clearenv()` before container exec | `scorpiox-unshare.c` | ✅ Good — clean environment |
| `fork()+execlp()` for editor (avoiding `system()`) | `sx.c` line 662 | ✅ Good — prevents shell injection |
| Read-only host binary mount | `scorpiox-unshare.c` | ✅ Good — host binaries protected |
| EACCES guidance for KVM | `scorpiox-vm.c` | ✅ Good — guides users to `kvm` group instead of root |

### 9.2 Violations

| Violation | Location | Recommendation |
|---|---|---|
| **107 `system()` calls** across codebase | Various | Replace with `fork()+exec()` where possible; critical when arguments contain user input |
| **61 `popen()` calls** | Various | Replace with pipe+fork+exec for safety |
| **`--privileged` mode** skips user namespace | `scorpiox-unshare.c` line 2181 | Add warning banner; require explicit `--i-know-what-im-doing` flag |
| **No seccomp profile** for containers | `scorpiox-unshare.c` | Apply minimal seccomp-bpf filter |
| **No capability bounding set** | `scorpiox-unshare.c` | Drop capabilities after namespace setup |
| **SSH host key checking disabled** | `scorpiox-sshpass.c` line 42 | Add prominent warning; never enable by default |
| **TLS verification disabled** in child env | `scorpiox-traffic.c` | Scope to proxy CA only; don't blanket-disable all verification |
| **World-accessible `/tmp` files** | Multiple tools | Use `mkdtemp()` or `$XDG_RUNTIME_DIR` with restrictive permissions |
| **No IPC namespace** in containers | `scorpiox-unshare.c` | Add `CLONE_NEWIPC` |
| **No resource limits** beyond optional memory | `scorpiox-unshare.c` | Add PID limits, CPU quotas |

---

## 10. Risk Assessment

### 10.1 Risk Matrix

| Risk | Likelihood | Impact | Mitigation Status |
|---|:---:|:---:|---|
| Shell injection via `system()`/`popen()` | Medium | High | ⚠️ Partial — some paths use fork+exec |
| Container escape via missing IPC namespace | Low | Critical | ❌ Not mitigated |
| Container escape via missing seccomp | Low | Critical | ❌ Not mitigated |
| TLS MITM on `scorpiox-traffic` children | Medium | High | ❌ By design — needs scope limitation |
| SSH credential exposure (`scorpiox-sshpass`) | High | Medium | ⚠️ Documented as "dangerous" |
| Privilege escalation via `--privileged` | Low | Critical | ⚠️ Requires explicit flag + root |
| Tmpfile symlink attacks | Low | Medium | ❌ Not mitigated |
| CGI env var injection | Medium | Medium | ⚠️ Standard CGI practice |
| KVM escape via guest code | Very Low | Critical | ✅ Hardware-enforced (KVM) |
| Unix socket hijacking (`/tmp/sxmux/`) | Low | Medium | ❌ No socket authentication |

### 10.2 Top Recommendations

1. **Replace `system()`/`popen()` with `fork()+exec()`** in all paths where arguments may contain user-controlled data (estimated 40+ call sites at risk).

2. **Add `CLONE_NEWIPC` and `CLONE_NEWCGROUP`** to `scorpiox-unshare` clone flags for complete namespace isolation.

3. **Implement seccomp-bpf** filtering for container child processes — at minimum block `mount`, `reboot`, `kexec_load`, `open_by_handle_at`, `init_module`.

4. **Drop capabilities** after user namespace UID mapping with `capset()` — only retain those needed for container operation.

5. **Move `/tmp` files to user-owned directories**: Use `$XDG_RUNTIME_DIR` or `$HOME/.scorpiox/run/` instead of `/tmp` for sockets and temporary files.

6. **Scope TLS bypass in `scorpiox-traffic`**: Instead of `NODE_TLS_REJECT_UNAUTHORIZED=0`, only set `*_CA_BUNDLE` to the custom CA that includes both system + proxy CAs. Remove the blanket TLS disable variables.

7. **Add authentication to Unix domain sockets**: Use `SO_PEERCRED` to verify connecting client UID matches server UID for `sxmux` sessions.

---

## Appendix A: File-by-File Process Spawning Map

| File | system() | popen() | fork() | exec*() | CreateProcess |
|---|:---:|:---:|:---:|:---:|:---:|
| sx.c | 8 | 3 | 1 | 1 | — |
| scorpiox-server.c | — | — | 3 | 2 | — |
| scorpiox-unshare.c | 1 | — | — | 3 | — |
| scorpiox-vm.c | — | — | — | — | — |
| scorpiox-bash.c | — | — | 1 | 1 | 1 |
| scorpiox-traffic.c | — | — | 2 | 1 | — |
| scorpiox-wsl.c | — | — | — | — | 2+ |
| sxmux_session.c | — | — | 1 | — | 1 |
| sxtmux_backend_*.c | 4 | 2 | 1 | 1 | — |
| scorpiox-hook.c | many | — | many | many | — |
| scorpiox-agent.c | many | — | — | many | — |
| sxmail_maildir.c | 2 | — | — | — | — |
| (others) | distributed | distributed | distributed | distributed | distributed |

---

## Appendix B: Container Namespace Flag Comparison

| Namespace | scorpiox-unshare | Docker (default) | Podman (rootless) |
|---|:---:|:---:|:---:|
| User | ✅ | ❌ (opt-in) | ✅ |
| Mount | ✅ | ✅ | ✅ |
| PID | ✅ | ✅ | ✅ |
| UTS | ✅ | ✅ | ✅ |
| Network | ✅ | ✅ | ✅ |
| IPC | ❌ | ✅ | ✅ |
| Cgroup | ❌ | ✅ | ✅ |
| Seccomp | ❌ | ✅ | ✅ |
| AppArmor/SELinux | ❌ | ✅ (if available) | ✅ (if available) |

---

*Report generated by Security Audit Agent — 2026-04-28*
