📄 05-permissions.md
⬇ Download Raw

05 — Permissions, Process Spawning, Privilege Model & Sandboxing Audit

Audit Date: 2026-04-28 Codebase: scorpiox/clang Auditor: Security Audit Agent Scope: OS-level permissions, system access, process spawning, privilege model, and sandboxing

Executive Summary

The scorpiox codebase is a large, multi-binary C platform encompassing an AI agent shell (sx), a rootless container runtime (scorpiox-unshare), a KVM virtual machine runner (scorpiox-vm), a web server (scorpiox-server), a DNS server (scorpiox-dns), an email stack (IMAP/SMTP), a terminal multiplexer (sxmux), and numerous tool binaries. The project makes extensive use of process spawning (656+ call sites), interacts deeply with Linux namespaces and cgroups, and in most cases operates without elevated privileges. However, several components require or benefit from root access, and certain design choices warrant security attention.

Overall Risk Level: MEDIUM — The container runtime has strong namespace isolation by default, but the broad use of system()/popen() for shell command execution, a hardcoded SSH password, and the number of binaries that can spawn arbitrary processes create a meaningful attack surface.

1. Permissions Summary

ComponentRoot Required?Privilege LevelNotes
sx (main agent shell)NoUserSpawns editor, reads config
scorpiox-unshareNoUser (rootless containers)Can run as root for NFS/CIFS mounts
scorpiox-vmEffectively yesNeeds /dev/kvm + /dev/net/tun accessKVM group membership required
scorpiox-thunderbolt4YesRoot (BPF)Explicit geteuid() != 0 check
scorpiox-dnsDependsPort 53 requires root or CAP_NET_BIND_SERVICEDefault: 0.0.0.0:53
scorpiox-serverNoUserBinds to configurable port (default 7432)
scorpiox-bashNoUserExecutes shell commands as current user
scorpiox-hostNoUserHTTP session gateway, daemonizes via fork
scorpiox-sshpassNoUserHardcoded default password: "xboxone"
scorpiox-initNoUserTool loader; exec's into child processes
scorpiox-agentNoUserOrchestrates agent sessions
scorpiox-sdkNoUserHeavy process spawning via forkpty

2. Privilege Requirements

2.1 Components That Require Root

  • scorpiox-thunderbolt4 — The only binary with an explicit root check:
  •    // scorpiox-thunderbolt4.c:1406
    

    if (geteuid() != 0) { fprintf(stderr, "error: need root (sudo)\n"); return 1; }

    Required for BPF access on macOS to do raw Ethernet frame I/O over Thunderbolt.

  • scorpiox-vm — Needs /dev/kvm (read-write) and /dev/net/tun for TAP networking. Typically requires kvm group membership rather than root.
  • scorpiox-dns — Binds to UDP/TCP port 53 by default. Port < 1024 requires root or CAP_NET_BIND_SERVICE.
  • 2.2 Components That Benefit From Root

  • scorpiox-unshare — Designed as rootless, but detects root at runtime:
  •    // scorpiox-unshare.c:1821
    

    int skip_userns = (getuid() == 0);

    When running as root, it skips user namespace creation (matches Docker/Podman behavior) to enable NFS/CIFS bind-mounts inside containers.

  • scorpiox-wsl.c — Uses chroot within WSL overlayfs containers, which requires root inside the WSL distribution.
  • 2.3 No Privilege Escalation Detected

      // scorpiox-unshare.c:774
    

    / Non-root: must use newuidmap/newgidmap (setuid helpers) /


    3. Process Spawning Inventory

    Total process spawning call sites (non-vendor): 656

    3.1 Spawning Mechanisms

    MechanismCountFilesRisk Level
    system()~80+25+ filesHIGH — Passes strings to shell
    popen()~40+15+ filesHIGH — Shell-interpreted strings
    fork() + exec*()~100+20+ filesMEDIUM — Direct exec, no shell
    forkpty()~20+6 filesMEDIUM — PTY-based spawning
    clone()1scorpiox-unshare.cLOW — Container runtime (by design)
    CreateProcess (Windows)2sxmux_session.cLOW — Platform-specific

    3.2 Top Process Spawning Files

    FileCall SitesPurpose
    scorpiox-unshare.c34Container runtime — fork/clone/exec are core functionality
    scorpiox-sdk.c34Session orchestration — forkpty→containers
    sx_procmon.c32Process monitoring library
    scorpiox-agent.c17Agent orchestration — system()/popen()/execlp()
    sx_exec.c17Core command execution library
    scorpiox-bash.c11Shell command execution tool
    scorpiox-wsl.c11WSL container management
    sx_provider_claude_code.c12Claude Code provider — spawns Claude CLI
    sx_provider_codex.c11Codex provider — spawns OpenAI CLI
    scorpiox-server.c10CGI script execution via fork+exec

    3.3 Security-Sensitive Spawning Patterns

    Concern 1: system() with constructed strings
    // scorpiox-agent.c:382 — arbitrary git commands
    

    int ret = system(cmd);

    // sx.c:659 — editor invocation

    int ret = system(editor_cmd);

    // sxmail_maildir.c:704 — maildir operations

    if (system(cmd) != 0) {

    Concern 2: popen() with constructed commands
    // sxtmux_backend_tmux.c:42
    

    FILE *fp = popen("tmux list-sessions ...", "r");

    // scorpiox-agent.c:407

    FILE *fp = popen(cmd, "r");

    Concern 3: Hook script execution
    // scorpiox-hook.c:579 — executes user-supplied hook scripts
    

    FILE *pipe = popen(full_cmd, "r");

    // scorpiox-hook.c:640

    system(full_cmd);

    Hook scripts in .scorpiox/hooks// are executed with full user privileges. No sandboxing or validation of hook content.

    3.4 Process Monitoring

    The codebase includes a dedicated process monitoring subsystem (sx_procmon.c) using atomic counters to track:

    This is a positive security practice for leak detection and audit.


    4. Filesystem Access Scope

    4.1 Primary Access Paths

    Path PatternAccess TypeComponents
    ~/.scorpiox/ (SCORPIOX_HOME)R/WAll components — config, sessions, data
    /tmp/R/WMultiple — temp files, IPC sockets, slirp API
    /proc/, /sys/RContainer setup, terminal size, procfs
    /dev/kvmR/Wscorpiox-vm only
    /dev/net/tunR/Wscorpiox-vm (TAP networking)
    /dev/bpf*R/Wscorpiox-thunderbolt4 only (macOS)
    /dev/pts/, /dev/shm/R/WContainer runtime (mounted inside containers)
    /sys/fs/cgroup/sx-/R/Wscorpiox-unshare (cgroup v2 memory limits)
    /etc/resolv.confRContainer DNS setup
    /etc/subuid, /etc/subgidRUser namespace mapping
    /mnt/tools/, /mnt/apps/Rscorpiox-init (tool loading)
    Working directory (CWD)R/WVarious — config, sessions, git operations

    4.2 Filesystem Access Assessment


    5. System Call Analysis

    5.1 Kernel Interactions

    Syscall CategoryCountFilesNotes
    ioctl()50+scorpiox-vm.c, sx_term.c, mailKVM control, terminal size, socket config
    mmap()5scorpiox-vm.cGuest memory + VCPU run struct. PROT_READ\PROT_WRITE only (no PROT_EXEC)
    clone()1scorpiox-unshare.cNamespace creation with CLONE_NEW* flags
    pivot_root()1scorpiox-unshare.cContainer rootfs switch
    mount()30+scorpiox-unshare.cContainer filesystem setup
    signal()/sigaction()40+VariousSignal handling for cleanup, SIGPIPE ignore

    5.2 Notable Findings

    - ⚠️ Gap: The container runtime does not apply seccomp profiles, unlike Docker/Podman which filter ~40+ dangerous syscalls by default. - KVM_CREATE_VM, KVM_CREATE_VCPU, KVM_SET_USER_MEMORY_REGION, KVM_RUN

    - KVM_SET_SREGS, KVM_SET_REGS, KVM_SET_CPUID2

    - KVM_CREATE_IRQCHIP, KVM_CREATE_PIT2, KVM_IRQ_LINE


    6. Sandboxing / Isolation Model

    6.1 Container Runtime (scorpiox-unshare)

    The container runtime implements a rootless Linux container model similar to Podman:

    Namespace Isolation:
    NamespaceFlagStatusNotes
    Mount (mnt)CLONE_NEWNS✅ AlwaysFilesystem isolation
    PIDCLONE_NEWPID✅ AlwaysProcess isolation
    UTSCLONE_NEWUTS✅ AlwaysHostname isolation
    UserCLONE_NEWUSER✅ DefaultSkipped when running as root
    NetworkCLONE_NEWNET✅ DefaultOpt-out via --net host
    IPC❌ MissingNo CLONE_NEWIPC flag
    Cgroup❌ MissingNo CLONE_NEWCGROUP flag
    Filesystem Isolation: Network Isolation: Resource Limits: GPU Passthrough:

    6.2 Container Security Gaps

    GapSeverityDescription
    No seccomp filterMEDIUMContainers can invoke any syscall the user namespace allows
    No CLONE_NEWIPCLOWShared IPC namespace allows SysV IPC cross-container communication
    No CLONE_NEWCGROUPLOWContainer can see host cgroup hierarchy
    --privileged flagMEDIUMSkips user namespace entirely, runs as real root inside container
    No capability droppingLOWAll user-namespace capabilities available inside container

    6.3 KVM Virtual Machine (scorpiox-vm)

    6.4 WSL Container (scorpiox-wsl.c)


    7. IPC Mechanisms

    7.1 Pipe Usage (797+ call sites)

    IPC TypeUsageFiles
    Unix pipes (pipe())Parent-child communication, process I/Osx_exec.c, scorpiox-bash.c, scorpiox-server.c
    Named pipes (Windows)Multiplexer session protocolsxmux_session.c
    Unix domain sockets (AF_UNIX)Multiplexer daemon, slirp4netns APIsxmux_session.c, scorpiox-unshare.c
    PTY (forkpty())Terminal emulation for child processessx_pty.c, sx_bgtask.c, scorpiox-sdk.c
    TCP socketsHTTP server, DNS, email, host gatewayscorpiox-server.c, scorpiox-dns.c, scorpiox-host.c
    Signals (SIGTERM, SIGINT, SIGCHLD)Process lifecycle managementAll daemon-like components

    7.2 Notable IPC Patterns


    8. Environment Variable Handling

    8.1 Security-Sensitive Environment Variables

    VariableUsageRisk
    SCORPIOX_HOMEBase directory for all data/configLOW — data directory path
    PATHSet inside containers to standard dirsLOW — hardcoded safe value
    EDITOR, VISUALUsed to launch editor via system()MEDIUM — user-controlled path executed
    SHELLDefault shell in multiplexer panesLOW
    CONTAINER_PACKAGESPackages to install in containersMEDIUM — passed to package manager
    IMAGE_BASE_URLContainer image download URLMEDIUM — could redirect image downloads

    8.2 Positive Findings

      setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 1);
      

    9. Principle of Least Privilege Assessment

    9.1 Positive Practices

    PracticeStatusNotes
    Rootless by defaultContainer runtime uses user namespaces
    No unnecessary setuidNo binaries require setuid bit
    Process monitoringsx_procmon.c tracks all fork/pipe lifecycle
    Read-only mounts/sys read-only, volume :ro support
    Tmpfs for sensitive dirs/dev, /tmp, /run are independent tmpfs
    Namespace isolation5 of 7 namespaces used by default
    UID mappingFull subuid/subgid range mapping with newuidmap

    9.2 Violations / Gaps

    ViolationSeverityDescription
    Hardcoded SSH passwordHIGHscorpiox-sshpass has DEFAULT_PASSWORD "xboxone" — documented as "home lab only" but ships in production binary
    No seccomp profilesMEDIUMContainer runtime does not filter syscalls
    system() for shell commandsMEDIUM~80+ call sites pass constructed strings to shell — injection risk if inputs are not sanitized
    No IPC namespace isolationLOWCLONE_NEWIPC not used in container runtime
    No cgroup namespaceLOWCLONE_NEWCGROUP not used
    No privilege dropping in serversMEDIUMscorpiox-server binds port then continues as same user — no setuid(nobody) pattern
    CGI execution modelMEDIUMscorpiox-server fork+exec's scripts with CGI env vars — relies on script security
    Hook script executionMEDIUM.scorpiox/hooks/ scripts are executed without sandboxing
    --privileged flag existsMEDIUMDisables user namespace, grants real root in container
    Editor launch via system()LOWEDITOR env var value passed to system()

    10. Risk Assessment

    10.1 Critical Risks

    #RiskComponentMitigation
    1Hardcoded password in production binaryscorpiox-sshpassRemove default, require explicit -p flag
    2Shell injection via system()/popen()Multiple (25+ files)Replace with fork()+execv() pattern; use sx_exec.c library which already has safe exec

    10.2 High Risks

    #RiskComponentMitigation
    3No syscall filtering in containersscorpiox-unshareAdd seccomp-bpf profile matching Docker defaults
    4Unsandboxed hook executionscorpiox-hookExecute hooks in container/namespace or with reduced privileges
    5CGI script executionscorpiox-serverApply seccomp or namespace isolation to CGI children

    10.3 Medium Risks

    #RiskComponentMitigation
    6Missing IPC and cgroup namespacesscorpiox-unshareAdd CLONE_NEWIPC \CLONE_NEWCGROUP
    7IMAGE_BASE_URL from environmentscorpiox-unshare/scorpiox-vmValidate URL against allowlist or pin to HTTPS
    8No privilege dropping after port bindscorpiox-server, scorpiox-dnsDrop to unprivileged user after bind()
    9/tmp IPC socket race conditionssxmux, scorpiox-unshareUse $XDG_RUNTIME_DIR with restricted permissions

    10.4 Recommendations Summary

  • Eliminate system() calls where possible — the codebase already has sx_exec() with fork()+exec() and timeout support. Route all command execution through it.
  • Add seccomp-bpf to the container runtime — even a basic profile blocking kexec_load, reboot, mount (after setup), ptrace would significantly improve security.
  • Remove the hardcoded password from scorpiox-sshpass or gate it behind a build flag.
  • Add CLONE_NEWIPC | CLONE_NEWCGROUP to the default clone flags in scorpiox-unshare.
  • Drop privileges in long-running servers (scorpiox-server, scorpiox-dns) after binding ports.
  • Sandbox hook execution — run hooks in a child with reduced capabilities or inside a container.

  • Appendix A: File-by-File Process Spawning Count

    FileSpawning Calls
    scorpiox-unshare.c34
    scorpiox-sdk.c34
    sx_procmon.c32
    scorpiox-agent.c17
    sx_exec.c17
    sx.c13
    sx_provider_claude_code.c12
    scorpiox-bash.c11
    scorpiox-wsl.c11
    sx_provider_codex.c11
    scorpiox-whatsapp.c10
    scorpiox-server.c10
    scorpiox-docs.c9
    sx_systemprompt.c9
    sx_pty.c9
    sx_bridge.c8
    scorpiox-mirror-git.c7
    sx_bgtask.c7
    sx_provider_openai.c7
    sx_provider_gemini.c7

    Appendix B: Namespace Isolation Matrix

                        scorpiox-unshare    scorpiox-vm     scorpiox-wsl
    

    Mount NS ✅ CLONE_NEWNS N/A (KVM) ❌ chroot only

    PID NS ✅ CLONE_NEWPID N/A (KVM) ❌ No

    User NS ✅ CLONE_NEWUSER* N/A (KVM) ❌ No

    Network NS ✅ CLONE_NEWNET† ✅ TAP/bridge ❌ Host network

    UTS NS ✅ CLONE_NEWUTS N/A (KVM) ❌ No

    IPC NS ❌ Missing N/A (KVM) ❌ No

    Cgroup NS ❌ Missing N/A (KVM) ❌ No

    Seccomp ❌ None N/A (KVM) ❌ None

    Capability drop ❌ None N/A (KVM) ❌ None

    * Skipped when running as root

    † Opt-out via --net host

    Appendix C: Methodology

  • Recursive grep of all non-vendor .c and .h files for process spawning functions (fork, exec*, system, popen, posix_spawn, clone, vfork, CreateProcess, ShellExecute)
  • Recursive grep for privilege-related syscalls (setuid, setgid, chroot, capset, prctl, seccomp, pledge, unveil)
  • Recursive grep for kernel interactions (ioctl, ptrace, mmap, mprotect, signal handling)
  • Recursive grep for namespace/container calls (unshare, setns, clone, CLONE_NEW*, pivot_root, cgroup)
  • Recursive grep for environment variable manipulation (setenv, putenv, getenv of security-sensitive variables)
  • Recursive grep for IPC mechanisms (pipes, sockets, shared memory, signals)
  • Recursive grep for filesystem access (fopen, open, mkdir, unlink, etc.)
  • Manual code review of critical files: scorpiox-unshare.c, scorpiox-vm.c, sx_exec.c, scorpiox-bash.c, scorpiox-server.c, scorpiox-sshpass.c