# Data Handling, File I/O, Privacy & Encryption Audit

**Audit Date:** 2026-04-28  
**Codebase:** scorpiox/clang  
**Scope:** 222 source files (142,256 LOC excluding vendor code), plus vendored mbedTLS and yyjson  
**Auditor:** Security Audit Agent

---

## 1. Data Flow Summary

The scorpiox codebase is a multi-component C application comprising:

| Component | Purpose | Data Sensitivity |
|-----------|---------|-----------------|
| `sx` (main CLI) | AI coding assistant TUI | **HIGH** — handles API keys, user conversations, system prompts |
| `scorpiox-server` | HTTP server executing scripts | **HIGH** — JWT secrets, POST bodies, auth headers |
| `scorpiox-server-email` | SMTP/IMAP email server | **CRITICAL** — email content, user passwords, TLS keys, DKIM keys |
| `scorpiox-server-fetchtoken` | TCP→HTTP token proxy | **HIGH** — API keys, auth tokens |
| `scorpiox-server-http2tcp` | HTTP relay | **MEDIUM** — relay keys, proxied traffic |
| `scorpiox-sshpass` | SSH password wrapper | **CRITICAL** — plaintext passwords passed via CLI `-p` flag |
| `scorpiox-otp` | TOTP generator | **HIGH** — TOTP secrets passed via CLI `-s` flag |
| `scorpiox-beam` | File transfer | **LOW** — file data (no encryption) |
| `scorpiox-whatsapp` | WhatsApp bridge | **HIGH** — WhatsApp auth credentials, message content |
| `scorpiox-tmux` | Terminal multiplexer launcher | **MEDIUM** — env vars, container configs |
| `libsxutil` | Shared utilities | **HIGH** — config cascade, logging, session management |
| `libsxnet` | Network/API layer | **HIGH** — API keys, FRP crypto, HTTP requests/responses |

**Data flow path:**
```
User Input → sx TUI → libsxnet (API provider) → HTTP/TLS → Remote API
                  ↓
         .scorpiox/sessions/<id>/  (conversations, traffic, logs, config snapshots)
         .scorpiox/conversations/  (persistent conversation JSON)
         .scorpiox/traces/         (debug trace JSONL)
```

---

## 2. File I/O Inventory

### 2.1 Configuration Files (Read)

| File | Location | Contains Sensitive Data | Notes |
|------|----------|----------------------|-------|
| `scorpiox-env.txt` | `<exe_dir>/` | **YES** — API keys, passwords, secrets | Global config |
| `scorpiox-env.txt` | `.scorpiox/` (CWD) | **YES** — project-level overrides | Higher priority cascade |
| `scorpiox-env.txt` | `~/.config/scorpiox/` | **YES** — user-level config | User override |

Config cascade: Built-in defaults → exe_dir config → CWD project config

### 2.2 Session Data (Read/Write)

| File Pattern | Location | Content | Sensitivity |
|-------------|----------|---------|------------|
| `conversation.json` | `.scorpiox/sessions/<id>/` | Full conversation history | **HIGH** — may contain user code, secrets |
| `session.log` | `.scorpiox/sessions/<id>/` | Session log with timestamps | **MEDIUM** — debug data, API calls |
| `agent.log` | `.scorpiox/sessions/<id>/` | Agent-level log | **MEDIUM** |
| `events.jsonl` | `.scorpiox/sessions/<id>/` | Event stream | **MEDIUM** |
| `trace.jsonl` | `.scorpiox/sessions/<id>/` | Data flow traces | **HIGH** — API request/response data |
| `config-snapshot.txt` | `.scorpiox/sessions/<id>/` | Resolved config at session start | **MEDIUM** — sensitive keys are redacted (****) |
| `traffic/` | `.scorpiox/sessions/<id>/` | Raw HTTP request/response bodies | **CRITICAL** — full API payloads |
| `messages/` | `.scorpiox/sessions/<id>/` | Per-message files | **HIGH** |
| `meta.json` | `.scorpiox/sessions/<id>/` | Session metadata (timestamps) | **LOW** |
| `required_skills.txt` | `.scorpiox/sessions/<id>/` | Skill list | **LOW** |

### 2.3 Conversation Persistence (Read/Write)

| File Pattern | Location | Content | Sensitivity |
|-------------|----------|---------|------------|
| `<id>.json` | `.scorpiox/conversations/` | Complete conversation JSON | **HIGH** |
| `latest` | `.scorpiox/conversations/` | Symlink to latest conversation | **LOW** |

### 2.4 Email Server Files

| File | Purpose | Sensitivity |
|------|---------|------------|
| TLS cert/key | `EMAIL_TLS_CERT`, `EMAIL_TLS_KEY` config | **CRITICAL** — TLS private key |
| DKIM key | `EMAIL_DKIM_KEY` config | **CRITICAL** — DKIM RSA private key |
| Accounts file | `EMAIL_ACCOUNTS_FILE` config | **CRITICAL** — user:hash pairs |
| Maildir | `EMAIL_MAILDIR` config | **CRITICAL** — email content |
| Aliases file | `EMAIL_ALIASES_FILE` config | **LOW** |
| Mail queue | `.scorpiox/mail-queue/` | **HIGH** — queued email content |

### 2.5 HTTP Server Temporary Files

| File Pattern | Location | Created By | Cleaned Up |
|-------------|----------|-----------|------------|
| `sx_post_<pid>_<time>.txt` | `/tmp/` (Linux) or `%TEMP%` (Windows) | `scorpiox-server` | **YES** — `unlink()` after script execution |

### 2.6 Socket/PID Files (sxmux)

| File Pattern | Location | Purpose |
|-------------|----------|---------|
| `<session>.sock` | `SXMUX_SOCKET_DIR` | Unix domain socket |
| `<session>.pid` | Socket dir | PID file for stale detection |

Socket directory created with `mkdir(..., 0700)` — ✅ Correct permissions.

### 2.7 WhatsApp Auth Data

| File Pattern | Location | Sensitivity |
|-------------|----------|------------|
| `creds.json` | `.scorpiox/whatsapp/auth/` | **CRITICAL** — WhatsApp session credentials |
| Message files | `WA_INBOX_DIR` | **HIGH** — message content |

---

## 3. PII Assessment

### 3.1 Directly Handled PII

| PII Type | Where | Context |
|----------|-------|---------|
| Email addresses | `scorpiox-server-email` | SMTP FROM/TO, JWT `user_email` claim |
| User identifiers | `scorpiox-server` JWT | `user_id`, `user_email` in JWT payload |
| Conversation content | `sx` main, session files | User prompts may contain any data |
| WhatsApp messages | `scorpiox-whatsapp` | Message body, sender info |

### 3.2 Indirect PII Exposure

- **Session traffic files** (`.scorpiox/sessions/<id>/traffic/`) contain raw API request/response bodies, which may include any user-submitted content
- **Conversation JSON files** persist all user messages including potentially sensitive content
- **Trace JSONL files** record API payloads at multiple checkpoints (API_REQUEST, API_RESPONSE, TOOL_USE_ADD)

### 3.3 PII Mitigation

- ✅ Sessions stored under `.scorpiox/sessions/` which is auto-added to `.gitignore`
- ✅ Session retention cleanup via `sx_session_cleanup_old()` with configurable `SESSION_RETENTION_DAYS`
- ⚠️ No encryption of data at rest for session/conversation files
- ⚠️ Conversation files in `.scorpiox/conversations/` are NOT auto-added to `.gitignore`

---

## 4. Credential Management

### 4.1 Built-in Default Credentials

**FINDING — MEDIUM RISK:** The config defaults table in `sx_config.c` contains:

| Key | Default Value | Risk |
|-----|--------------|------|
| `OPENAI_API_KEY` | `"xxx"` | Low — placeholder, not a real key |
| `ANTHROPIC_ANTIGRAVITY_URL` | `http://192.168.1.12:8045/v1/messages` | **MEDIUM** — hardcoded internal IP leaks network topology |
| `ANTHROPIC_ZAI_URL` | `https://api.z.ai/api/anthropic/v1/messages` | Low — public URL |
| `TCP_HOST` | `proxy.scorpiox.net` | Low — public hostname |
| All `*_SSH_PASS`, `*_SSH_USER`, `*_SSH_HOST` | `""` (empty) | ✅ Correctly defaulted to empty |
| All `*_API_KEY` (except OpenAI) | `""` (empty) | ✅ Correctly defaulted to empty |

### 4.2 Config File Credential Storage

Credentials are stored in plaintext `scorpiox-env.txt` files as `KEY=VALUE` pairs. Sensitive keys include:

- `ANTHROPIC_API_KEY`, `ANTHROPIC_ANTIGRAVITY_KEY`, `ANTHROPIC_ZAI_KEY`
- `GEMINI_API_KEY`, `OPENAI_API_KEY`
- `CODEX_SSH_PASS`, `CLAUDE_CODE_SSH_PASS`
- `SERVER_JWT_SECRET`
- `HTTP_RELAY_KEY`, `FETCHTOKEN_API_KEY`
- `SMTP_PASS`, `EMAIL_RELAY_PASS`

**FINDING — HIGH RISK:** All credentials stored as plaintext in config files. No encryption, no OS keychain integration, no vault support.

### 4.3 Credential Redaction

✅ **GOOD:** `sx_config_is_sensitive()` correctly identifies sensitive keys by checking for substrings: `KEY`, `PASS`, `SECRET`, `TOKEN`, `CREDENTIAL` (case-insensitive).

✅ **GOOD:** Config snapshot in session files redacts sensitive values to `****`.

✅ **GOOD:** Startup logging masks keys containing "KEY" as `***`.

⚠️ **GAP:** Logging only masks keys matching `strstr(keys[k], "KEY")` — this misses `*_PASS` and `*_SECRET` keys in the startup log (though `snapshot_write_entry` uses the comprehensive `sx_config_is_sensitive()`).

### 4.4 Runtime Credential Handling

| Mechanism | Implementation | Risk |
|-----------|---------------|------|
| JWT validation | HMAC-SHA256 with constant-time compare | ✅ Secure |
| JWT secret | Loaded from `SERVER_JWT_SECRET` config | Plaintext in config |
| API keys → HTTP headers | Passed as Authorization/x-api-key headers | ✅ Normal pattern |
| FRP token | PBKDF2-derived AES key | ✅ Good KDF usage |
| SSH passwords (`scorpiox-sshpass`) | Passed via `-p` CLI argument | **CRITICAL** — visible in `ps` output |
| TOTP secrets (`scorpiox-otp`) | Passed via `-s` CLI argument | **HIGH** — visible in `ps` output |
| SMTP auth (email server) | SHA-256 hashed passwords in accounts file | ⚠️ No salt, no KDF |
| Authorization header | Passed through to CGI scripts via `HTTP_AUTHORIZATION` env var | ⚠️ Exposed to child processes |

### 4.5 Token Proxy Security

`scorpiox-server-fetchtoken`:
- API key comparison uses `strcmp()` — ⚠️ **Not constant-time** (timing side-channel possible)
- API key logged as `***` — ✅ Good
- Key comes from config, not hardcoded — ✅ Good

---

## 5. Encryption Usage

### 5.1 In-Transit Encryption

| Component | Protocol | Library | Verification |
|-----------|----------|---------|-------------|
| `sxmail_tls.c` | TLS 1.2 (server) | mbedTLS | ✅ Proper certificate loading, entropy seeding |
| `sx_frp.c` | AES-128-CFB stream cipher | mbedTLS | ✅ PBKDF2-SHA1 key derivation |
| `sx_http.c` (via providers) | HTTPS | mbedTLS TLS client | Config: `CLAUDE_CODE_PROXY_STRICT` controls cert verification |
| `scorpiox-beam` | **NONE** | N/A | **RISK** — file transfer over raw TCP with only xxHash64 integrity |

### 5.2 Crypto Primitives Used

| Algorithm | Location | Purpose | Assessment |
|-----------|----------|---------|------------|
| AES-128-CFB | `sx_frp.c` | FRP control stream encryption | ✅ Appropriate for stream cipher |
| PBKDF2-SHA1 | `sx_frp.c` | FRP key derivation | ⚠️ Only 64 iterations — very low; SHA-1 is deprecated for new designs |
| SHA-256 | `scorpiox-server.c` | JWT HMAC-SHA256 signature | ✅ Industry standard |
| SHA-256 | `sxmail_auth.c` | Password hashing | ⚠️ **No salt, no KDF** — vulnerable to rainbow tables |
| SHA-1 | `scorpiox-otp.c` | HMAC-SHA1 for TOTP (RFC 6238) | ✅ Required by TOTP spec |
| MD5 | `sx_frp.c` | FRP login hash | ⚠️ MD5 is cryptographically broken |
| RSA | `sxmail_dkim.c` | DKIM signing | ✅ Via mbedTLS |
| TLS 1.2 | `sxmail_tls.c`, `sx_frp.c` | Transport security | ✅ mbedTLS implementation |

### 5.3 Encryption at Rest

**FINDING — HIGH RISK:** No encryption at rest is used anywhere in the codebase. All persistent data (conversations, sessions, config files, email maildir, WhatsApp credentials) is stored in plaintext on the filesystem.

### 5.4 mbedTLS Configuration

`sx_mbedtls_config.h` enables:
- AES-128-CFB (cipher mode)
- PBKDF2 (via PKCS5)
- TLS 1.2 (client + server)
- RSA, X.509 certificates
- SHA-1, SHA-256, SHA-384, SHA-512
- CTR-DRBG entropy

**Note:** TLS 1.3 is NOT enabled. Only TLS 1.2 is configured.

---

## 6. Temporary File Security

### 6.1 POST Body Temp Files (`scorpiox-server`)

```c
// Linux path construction:
snprintf(tmppath, sizeof(tmppath), "/tmp/sx_post_%d_%ld.txt",
         sx_getpid(), (long long)time(NULL));
```

**FINDINGS:**
- ⚠️ **Predictable filenames** — uses PID + timestamp, which are guessable → symlink attack risk
- ⚠️ **No `mkstemp()`** — uses `fopen()` with constructed path instead of secure temp file creation
- ✅ Files are cleaned up via `unlink()` after use
- ⚠️ **Race condition** — gap between name construction and `fopen()` allows TOCTOU attack

### 6.2 Other Temporary Usage

- `sxmux_session.c` creates socket directory with `mkdir(..., 0700)` — ✅ Correct permissions
- No other temporary file creation patterns found outside of vendor code

---

## 7. Logging Analysis

### 7.1 Log Architecture

- **File logging:** Session logs to `.scorpiox/sessions/<id>/session.log`
- **Stderr logging:** Fallback when file logging fails
- **Log levels:** ERROR, WARN, INFO, DEBUG, TRACE (configurable via `LOG_LEVEL`)
- **Timestamps:** Millisecond precision `[HH:MM:SS.mmm]`

### 7.2 Sensitive Data in Logs

| Log Entry | Risk | Mitigation |
|-----------|------|-----------|
| Config values at startup | Keys with "KEY" substring masked as `***` | ⚠️ Incomplete — `*_PASS`, `*_SECRET` not masked in startup log |
| SMTP auth success/failure | Logs username only | ✅ Password not logged |
| JWT validation failure | Logs "signature verification failed" | ✅ No secret/token logged |
| FRP token | Not logged | ✅ Good |
| API request/response bodies | Written to `traffic/` dir (separate from logs) | ⚠️ Contains full API payloads |
| DKIM key path | Logged at INFO level | ✅ Path only, not key content |
| `fetchtoken` API key | Logged as `***` | ✅ Good |

### 7.3 Trace System

The trace system (`sx_trace.c`) writes detailed data flow checkpoints to `.scorpiox/traces/<session>.jsonl` and/or `.scorpiox/sessions/<id>/trace.jsonl`:

- `API_REQUEST` — full request being sent
- `API_RESPONSE` — full response received
- `TOOL_USE_ADD` — tool call details
- `CONV_SAVE` / `CONV_LOAD` — conversation state

**FINDING — HIGH RISK:** Trace data may contain API keys in HTTP headers and full conversation content. Trace files have no special access controls.

### 7.4 Log File Locations

| Log | Path | Created By |
|-----|------|-----------|
| Session log | `.scorpiox/sessions/<id>/session.log` | `sx` main |
| Agent log | `.scorpiox/sessions/<id>/agent.log` | `sx` main |
| Fallback log | `.scorpiox/logs/sx-session.log` | `sx` main |
| Email server log | `~/.scorpiox/server-email.log` | `scorpiox-server-email` |
| Trace | `.scorpiox/sessions/<id>/trace.jsonl` | `sx_trace.c` |

---

## 8. Environment Variable Usage

### 8.1 Environment Variables Read

| Variable | Read By | Sensitivity |
|----------|---------|------------|
| `HOME` / `USERPROFILE` | Multiple | Low — path discovery |
| `SHELL` | `sxmux_pane.c` | Low — default shell |
| `EDITOR` / `VISUAL` | `sx.c` | Low — editor selection |
| `ENABLE_TERM_BACKGROUND` | `sx_term.c` | Low — UI config |
| `SXMUX_INIT_CMD` | `sxmux_pane.c` | Low — pane init command |

### 8.2 Environment Variables Set (for child processes)

| Variable | Set By | Contains | Risk |
|----------|--------|----------|------|
| `HTTP_AUTHORIZATION` | `scorpiox-server.c` | Auth header value | **HIGH** — full Authorization header passed to CGI scripts |
| `POST_BODY_FILE` | `scorpiox-server.c` | Temp file path | Low — path only |
| Various CGI vars | `scorpiox-server.c` | Query params, headers | Medium — depends on content |

### 8.3 Config System vs Environment

The codebase uses its own `sx_config_get()` system rather than raw `getenv()` for most configuration. The config cascade (defaults → file → file) avoids polluting the process environment with secrets. This is a good pattern.

**Exception:** `scorpiox-sshpass` passes password via `write()` to PTY (not env var), which is better than `SSHPASS` env var but the password is still visible in `/proc/<pid>/cmdline` via the `-p` argument.

---

## 9. Data Retention

### 9.1 Session Retention

- Configurable via `SESSION_RETENTION_DAYS` config key
- `sx_session_cleanup_old()` purges sessions older than the retention period
- Default: not set (sessions persist indefinitely)
- Cleanup triggers: at session creation time

### 9.2 Conversation Retention

- No automatic cleanup mechanism found for `.scorpiox/conversations/` files
- Conversations persist indefinitely

### 9.3 Email Retention

- Maildir-based storage with no automatic expiration found in audited code
- Queue messages persist until relay delivery

### 9.4 Trace/Log Retention

- No automatic cleanup for trace files or log files independent of session cleanup
- If session is deleted, associated logs/traces are removed

---

## 10. Risk Assessment

### Critical Risks

| ID | Finding | Location | Impact |
|----|---------|----------|--------|
| **C-1** | SSH passwords visible in process listing | `scorpiox-sshpass` `-p` flag | Password exposure to any user who can run `ps` |
| **C-2** | Email password hashing uses unsalted SHA-256 | `sxmail_auth.c` | Rainbow table attacks on stolen accounts file |
| **C-3** | No encryption at rest for any persistent data | All components | Data breach exposure if filesystem is compromised |

### High Risks

| ID | Finding | Location | Impact |
|----|---------|----------|--------|
| **H-1** | All credentials stored as plaintext in config files | `scorpiox-env.txt` | Credential theft via file access |
| **H-2** | TOTP secrets visible in process listing | `scorpiox-otp` `-s` flag | TOTP secret exposure |
| **H-3** | Session traffic dir contains full API payloads | `.scorpiox/sessions/*/traffic/` | API keys in headers, conversation content |
| **H-4** | Trace files contain unredacted API data | `.scorpiox/sessions/*/trace.jsonl` | Same as H-3 |
| **H-5** | FRP PBKDF2 uses only 64 iterations | `sx_frp.c` | Brute-force key derivation feasible |
| **H-6** | FRP login uses MD5 hash | `sx_frp.c` | MD5 is cryptographically broken |
| **H-7** | Predictable temp file names (no mkstemp) | `scorpiox-server.c` | Symlink / TOCTOU attacks on `/tmp/sx_post_*` |

### Medium Risks

| ID | Finding | Location | Impact |
|----|---------|----------|--------|
| **M-1** | Hardcoded internal IP `192.168.1.12` in defaults | `sx_config.c` | Network topology leak |
| **M-2** | `fetchtoken` API key comparison not constant-time | `scorpiox-server-fetchtoken.c` | Timing side-channel |
| **M-3** | Startup log masks only "KEY"-containing config names | `sx.c` | `*_PASS`, `*_SECRET` values logged in cleartext |
| **M-4** | TLS 1.2 only (no TLS 1.3) | `sx_mbedtls_config.h` | Missing modern TLS features |
| **M-5** | `scorpiox-beam` file transfer has no encryption | `scorpiox-beam.c` | Data in transit is unprotected |
| **M-6** | Conversations dir not in `.gitignore` auto-management | `sx_conversation.c` | Accidental commit of conversation data |
| **M-7** | Authorization header passed to CGI via env var | `scorpiox-server.c` | Credential leakage to untrusted scripts |
| **M-8** | No conversation retention/cleanup mechanism | `sx_conversation.c` | Data hoarding risk |

### Positive Findings

| ID | Finding | Location |
|----|---------|----------|
| **P-1** | Config snapshot correctly redacts sensitive keys via `sx_config_is_sensitive()` | `sx_session.c`, `sx_config.c` |
| **P-2** | Session data auto-added to `.gitignore` | `sx_session.c` |
| **P-3** | JWT uses constant-time signature comparison | `scorpiox-server.c` |
| **P-4** | Socket directory created with `0700` permissions | `sxmux_session.c` |
| **P-5** | POST body temp files cleaned up after use | `scorpiox-server.c` |
| **P-6** | No hardcoded real API keys or passwords in source | `sx_config.c` |
| **P-7** | Config system avoids env var pollution (uses own cascade) | `sx_config.c` |
| **P-8** | FRP uses proper AES-128-CFB with random IV | `sx_frp.c` |
| **P-9** | TLS implementation via well-maintained mbedTLS library | `sxmail_tls.c` |

---

## 11. Recommendations

1. **Replace unsalted SHA-256 password hashing** with Argon2id or bcrypt (C-2)
2. **Use `mkstemp()` for temp files** instead of predictable name construction (H-7)
3. **Increase PBKDF2 iterations** from 64 to at least 100,000 (H-5)
4. **Add encryption at rest** for session/conversation data or at minimum restrict file permissions to `0600` (C-3)
5. **Use environment variable or stdin** for `scorpiox-sshpass` password instead of CLI `-p` (C-1)
6. **Add constant-time comparison** for `fetchtoken` API key validation (M-2)
7. **Extend startup log masking** to cover `*_PASS` and `*_SECRET` patterns (M-3)
8. **Enable TLS 1.3** in mbedTLS configuration (M-4)
9. **Add encryption to `scorpiox-beam`** file transfers (M-5)
10. **Add conversation cleanup** mechanism similar to session retention (M-8)
11. **Remove hardcoded internal IP** from config defaults (M-1)
12. **Consider redacting Authorization headers** in traffic/trace files (H-3, H-4)

