📄 05-permissions.md
⬇ Download Raw

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 LevelComponentReason
🔴 CRITICALscorpiox-trafficDisables TLS verification globally for child processes
🔴 CRITICALscorpiox-sshpassDisables all SSH host key checking by design
🟠 HIGHscorpiox-unshareContainer runtime with --privileged mode bypassing user namespaces
🟠 HIGHscorpiox-vmDirect KVM access via /dev/kvm ioctls, mmap of guest memory
🟠 HIGHscorpiox-serverFork-per-request model executing arbitrary Python scripts via execlp
🟠 HIGHscorpiox-thunderbolt4Requires root for raw BPF Ethernet frame access
🟡 MEDIUMsx.c (main TUI)Extensive system()/popen() calls for subcommand dispatch
🟡 MEDIUMsxmux_sessionDaemon fork with Unix domain sockets in /tmp/sxmux
🟢 LOWscorpiox-podmanThin wrapper delegating to Podman; no direct privilege use

2. Privilege Requirements

2.1 Components Requiring Root/Elevated Privileges

ComponentPrivilege RequiredReason
scorpiox-thunderbolt4Root (sudo)Opens /dev/bpf* for raw Ethernet frames (line 1410: geteuid() != 0 check)
scorpiox-unshare --privilegedRootSkips user namespace, runs container as real root (line 2182: getuid() != 0 check)
scorpiox-vmkvm groupOpens /dev/kvm (O_RDWR) for hardware virtualization (line 1997)
scorpiox-unshare (cgroup memory)Root or cgroup2 delegationCreates cgroup dirs at /sys/fs/cgroup/sx-/ (line 881)

2.2 Components Running as Unprivileged User

The majority of tools run as the invoking user:

2.3 No setuid/setgid Binary Installation

The codebase does not install setuid binaries. It references external setuid helpers:

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)

MechanismCountRisk Level
system()107🟠 HIGH — shell injection surface
exec*() family66🟡 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): 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

3.2.3 clone() with Namespace Flags

scorpiox-unshare.c line 1831:
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:

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

3.2.4 fork() + exec*() Patterns

3.2.5 CreateProcessA() (Windows)


4. Filesystem Access Scope

4.1 Directories Accessed

Path PatternComponentAccess Type
~/.scorpiox/All toolsR/W — config, sessions, conversations, logs
.scorpiox/ (CWD-relative)sx.c, agentsR/W — sessions, hooks, skills
/tmp/sxmux/sxmux_sessionR/W — Unix socket dir, PID files
/tmp/sx_VariousR/W — temporary files (voice, emit, slirp sockets)
/proc//uid_map, gid_map, setgroupsscorpiox-unshareW — user namespace setup
/sys/fs/cgroup/sx-/scorpiox-unshareR/W — memory cgroup
/etc/subuid, /etc/subgidscorpiox-unshareR (W if root) — UID mapping
/dev/kvmscorpiox-vmR/W — KVM hypervisor
/dev/net/tunscorpiox-vmR/W — TAP networking
/dev/bpfscorpiox-thunderbolt4R/W — raw Ethernet
/var/mail/sxmail_*R/W — mail storage
/usr/lib/scorpiox/vmlinuzscorpiox-vmR — default kernel
/opt/scorpiox-agent/scorpiox-agentR/W — agent cache

4.2 Container Filesystem Mounts

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

MountTypeFlags
/ (root)MS_REC \MS_PRIVATEPrevents mount propagation to host
rootfsoverlayfs or bindMS_NODEV on overlay
/devtmpfsMS_NOSUID
/dev/ptsdevptsMS_NOSUID \MS_NOEXEC
/dev/shmtmpfsMS_NOSUID \MS_NODEV
/procprocfsMS_NOSUID \MS_NODEV \MS_NOEXEC
/syssysfsMS_NOSUID \MS_NODEV \MS_NOEXEC \MS_RDONLY
/tmptmpfsMS_NOSUID \MS_NODEV
/runtmpfsMS_NOSUID \MS_NODEV
/workspacebind (host dir)Optional: --bind flag
/persistbind (host dir)Optional: --persist flag
/opt/host-binbind (host exe dir)Read-only (host binaries)
GPU devicesbindOptional: --gpu flag
Positive: Mount flags consistently use MS_NOSUID, MS_NODEV, and MS_NOEXEC where appropriate.

4.3 Filesystem Access Concerns

  • 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.
  • 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.
  • 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:

    ioctlPurposeLine
    KVM_GET_API_VERSIONAPI compatibility check2007
    KVM_CREATE_VMCreate VM instance2021
    KVM_SET_TSS_ADDRTSS configuration2027
    KVM_CREATE_IRQCHIPInterrupt controller2030
    KVM_CREATE_PIT2Timer (PIT)2034
    KVM_SET_USER_MEMORY_REGIONMap guest memory (×3)2055, 2067, 2085
    KVM_CREATE_VCPUCreate virtual CPU2096
    KVM_GET_VCPU_MMAP_SIZEvCPU run struct size2102
    KVM_GET_SUPPORTED_CPUIDCPU feature detection2123
    KVM_SET_CPUID2Set guest CPUID2144
    KVM_GET_SREGS/KVM_SET_SREGSSegment registers2384, 2443
    KVM_SET_REGSGeneral-purpose registers2455
    KVM_IRQ_LINEInject interrupts917, 1463, 1538, 1897, 1969

    5.2 mmap Usage (scorpiox-vm.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)

    // 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


    6. Sandboxing / Isolation Model

    6.1 scorpiox-unshare — Linux Container Runtime

    Architecture: Rootless container using Linux user namespaces.

    Namespace Isolation

    NamespaceUsedNotes
    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
    IPCNot isolated — shares host IPC
    CgroupNot isolated — v2 memory limits only

    Rootfs Isolation

    Network Isolation

    Resource Limits

    Environment Sanitization

    6.2 scorpiox-vm — KVM Virtual Machine

    Architecture: Full hardware-level isolation via KVM.

    6.3 scorpiox-wsl — WSL2 Execution

    Architecture: Delegates to Windows WSL2 infrastructure.

    6.4 scorpiox-podman — Podman Wrapper

    Architecture: Thin CLI wrapper delegating to Podman.

    6.5 Sandboxing Gaps

    GapImpactRecommendation
    No IPC namespace in scorpiox-unshareContainer can access host System V IPC (shared memory, semaphores, message queues)Add CLONE_NEWIPC to clone flags
    No cgroup namespace isolationContainer can see host cgroup hierarchyAdd CLONE_NEWCGROUP
    No seccomp filterContainer processes can invoke all syscallsApply seccomp-bpf filter for container child
    No capability droppingRoot-in-userns retains all user-namespace capabilitiesDrop unnecessary capabilities with prctl(PR_SET_KEEPCAPS) + capset()
    /proc/sys/kernel/random synthetic mountOnly provides static file contents (uuid, boot_id) — not cryptographically validDocument limitation; consider bind-mounting from host

    7. IPC Mechanisms

    7.1 Unix Domain Sockets

    sxmux_session.c: Terminal multiplexer daemon communication. 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):

    7.3 Pipes (Anonymous)

    Used extensively for parent-child communication:

    ComponentPurpose
    scorpiox-unshare.csync_pipe — UID map readiness signal (line 1787)
    scorpiox-unshare.cnet_pipe — network namespace readiness (line 1805)
    scorpiox-server.cstdin_pipe/stdout_pipe — CGI I/O (line 1660)
    scorpiox-bash.cstdin/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


    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():

    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():

    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:

    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


    9. Principle of Least Privilege Assessment

    9.1 Positive Patterns

    PatternLocationAssessment
    User namespaces for rootless containersscorpiox-unshare.c✅ Excellent — no root needed for basic containers
    O_CLOEXEC on sensitive file descriptorsscorpiox-vm.c (KVM, TUN)✅ Good — prevents FD leaks to children
    MS_NOSUIDMS_NODEVMS_NOEXEC mount flagsscorpiox-unshare.c✅ Good — restricts container mount capabilities
    clearenv() before container execscorpiox-unshare.c✅ Good — clean environment
    fork()+execlp() for editor (avoiding system())sx.c line 662✅ Good — prevents shell injection
    Read-only host binary mountscorpiox-unshare.c✅ Good — host binaries protected
    EACCES guidance for KVMscorpiox-vm.c✅ Good — guides users to kvm group instead of root

    9.2 Violations

    ViolationLocationRecommendation
    107 system() calls across codebaseVariousReplace with fork()+exec() where possible; critical when arguments contain user input
    61 popen() callsVariousReplace with pipe+fork+exec for safety
    --privileged mode skips user namespacescorpiox-unshare.c line 2181Add warning banner; require explicit --i-know-what-im-doing flag
    No seccomp profile for containersscorpiox-unshare.cApply minimal seccomp-bpf filter
    No capability bounding setscorpiox-unshare.cDrop capabilities after namespace setup
    SSH host key checking disabledscorpiox-sshpass.c line 42Add prominent warning; never enable by default
    TLS verification disabled in child envscorpiox-traffic.cScope to proxy CA only; don't blanket-disable all verification
    World-accessible /tmp filesMultiple toolsUse mkdtemp() or $XDG_RUNTIME_DIR with restrictive permissions
    No IPC namespace in containersscorpiox-unshare.cAdd CLONE_NEWIPC
    No resource limits beyond optional memoryscorpiox-unshare.cAdd PID limits, CPU quotas

    10. Risk Assessment

    10.1 Risk Matrix

    RiskLikelihoodImpactMitigation Status
    Shell injection via system()/popen()MediumHigh⚠️ Partial — some paths use fork+exec
    Container escape via missing IPC namespaceLowCritical❌ Not mitigated
    Container escape via missing seccompLowCritical❌ Not mitigated
    TLS MITM on scorpiox-traffic childrenMediumHigh❌ By design — needs scope limitation
    SSH credential exposure (scorpiox-sshpass)HighMedium⚠️ Documented as "dangerous"
    Privilege escalation via --privilegedLowCritical⚠️ Requires explicit flag + root
    Tmpfile symlink attacksLowMedium❌ Not mitigated
    CGI env var injectionMediumMedium⚠️ Standard CGI practice
    KVM escape via guest codeVery LowCritical✅ Hardware-enforced (KVM)
    Unix socket hijacking (/tmp/sxmux/)LowMedium❌ No socket authentication

    10.2 Top Recommendations

  • Replace system()/popen() with fork()+exec() in all paths where arguments may contain user-controlled data (estimated 40+ call sites at risk).
  • Add CLONE_NEWIPC and CLONE_NEWCGROUP to scorpiox-unshare clone flags for complete namespace isolation.
  • Implement seccomp-bpf filtering for container child processes — at minimum block mount, reboot, kexec_load, open_by_handle_at, init_module.
  • Drop capabilities after user namespace UID mapping with capset() — only retain those needed for container operation.
  • Move /tmp files to user-owned directories: Use $XDG_RUNTIME_DIR or $HOME/.scorpiox/run/ instead of /tmp for sockets and temporary files.
  • 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.
  • 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

    Filesystem()popen()fork()exec()CreateProcess
    sx.c8311
    scorpiox-server.c32
    scorpiox-unshare.c13
    scorpiox-vm.c
    scorpiox-bash.c111
    scorpiox-traffic.c21
    scorpiox-wsl.c2+
    sxmux_session.c11
    sxtmux_backend_.c4211
    scorpiox-hook.cmanymanymany
    scorpiox-agent.cmanymany
    sxmail_maildir.c2
    (others)distributeddistributeddistributeddistributeddistributed

    Appendix B: Container Namespace Flag Comparison

    Namespacescorpiox-unshareDocker (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