Files
firefrost-operations-manual/docs/tasks-index/task-112-trinity-core-security.md
Claude 33a29d0946 task: Complete Tasks #109, #111, #112
#109 MCP Logging — Fully operational. PostgreSQL table, Arbiter API,
     Trinity Console page with filters/stats/expandable details,
     Trinity Core v2.3.0 POSTs logs after every command.

#111 Trinity Core Web MCP — Completed by Chronicler #77.
     Claude.ai native connector working since Apr 11.

#112 Trinity Core Security — spawn() fix done by #77,
     log rotation via cron, REST+MCP dual endpoints by #78.

Chronicler #78 | firefrost-operations-manual
2026-04-11 11:56:24 +00:00

187 lines
4.7 KiB
Markdown

---
task_number: 112
title: Trinity Core Security Hardening
status: Complete
priority: P1-High
is_blocker: true
owner: Michael
tags:
- trinity-core
- security
- infrastructure
estimated_hours: 3
---
# Trinity Core Security Hardening
Address security concerns identified by Gemini before deploying web MCP upgrade.
## Why This is a Blocker
Trinity Core provides root SSH access to 7 production servers. Before enabling multi-user access (Holly, Meg) or native Claude.ai integration, we must address these vulnerabilities.
---
## Issue 1: Command Injection (CRITICAL)
**The Problem:**
Current code:
```javascript
const sshCmd = `ssh -o ConnectTimeout=10 ${target.user}@${target.host} "${command.replace(/"/g, '\\"')}"`;
exec(sshCmd, ...);
```
This only escapes double quotes. Subshells `$(...)`, backticks `` `...` ``, and environment variables `$VAR` are NOT escaped. A prompt injection attack could execute arbitrary commands.
**Example Attack:**
```
Command: echo $(cat /etc/shadow)
Result: Dumps password hashes
```
**The Fix:**
Use `child_process.spawn` with array arguments instead of `exec` with string interpolation:
```javascript
import { spawn } from 'child_process';
function executeCommand(server, command) {
return new Promise((resolve, reject) => {
const target = SERVERS[server];
// spawn prevents shell interpretation
const ssh = spawn('ssh', [
'-o', 'ConnectTimeout=10',
`${target.user}@${target.host}`,
command // passed as single argument, not interpolated into shell
]);
let stdout = '';
let stderr = '';
ssh.stdout.on('data', (data) => stdout += data);
ssh.stderr.on('data', (data) => stderr += data);
ssh.on('close', (code) => {
resolve({
success: code === 0,
stdout: stdout.trim(),
stderr: stderr.trim(),
code
});
});
ssh.on('error', reject);
});
}
```
**Status:** ❌ Not implemented — MUST FIX before web MCP deployment
---
## Issue 2: AI Concurrency / Race Conditions (MEDIUM)
**The Problem:**
If Chronicler and Catalyst both run commands on the same server simultaneously:
- Catalyst restarts Docker
- Chronicler deploys container
- Chronicler's command fails or corrupts deployment
**The Fix:**
Add server locking to Arbiter:
```sql
CREATE TABLE server_locks (
server VARCHAR(50) PRIMARY KEY,
locked_by VARCHAR(50),
locked_at TIMESTAMP,
expires_at TIMESTAMP
);
```
Before executing, check lock. If locked, return:
*"tx1-dallas is currently locked by The Catalyst. Please try again in a moment."*
**Status:** ⏳ Future enhancement — not critical for initial deployment
---
## Issue 3: SD Card Wear & Log Exhaustion (HIGH)
**The Problem:**
- Pi SD cards have finite write cycles
- `fs.appendFileSync` on every command wears the card
- No log rotation = disk fills up
**The Fix (Implemented):**
Added cron job to rotate logs daily:
```
0 0 * * * truncate -s 0 /home/claude_executor/mcp-server/command.log && echo "[$(date -Iseconds)] Log rotated" >> /home/claude_executor/mcp-server/command.log
```
**Better Long-term Fix:**
Send logs to Arbiter's PostgreSQL instead of local disk (Task #109 already covers this).
**Status:** ✅ Mitigated with cron rotation
---
## Issue 4: Cloudflare Access Layer (MEDIUM)
**The Problem:**
`mcp.firefrostgaming.com` is public. Malicious requests hit the Pi even if rejected by auth.
**The Fix:**
Enable Cloudflare Access (Zero Trust) for the subdomain:
1. Only allow requests from Anthropic IP ranges
2. Or require Cloudflare Service Token header
3. Drops malicious traffic at edge before reaching Pi
**Status:** ⏳ Future enhancement — token auth is sufficient for now
---
## Issue 5: System Prompt Alignment (LOW)
**The Problem:**
AI partners won't know how to use Trinity Core unless told.
**The Fix:**
Update system prompts / project instructions for:
- Chronicler: Already has Trinity Core context in project instructions
- Catalyst: Add Trinity Core section to Catalyst project
- The Orb: Add Trinity Core section to Orb project
Include:
- Available servers
- How to run commands
- What requires approval
- What to do on timeout
**Status:** ⏳ Document when Catalyst/Orb projects are created
---
## Implementation Checklist
**Before Web MCP Deployment (Task #111):**
- [ ] Fix command injection with `spawn` instead of `exec`
- [ ] Verify log rotation is working
**After Initial Deployment:**
- [ ] Consider Cloudflare Access
- [ ] Consider server locking for concurrency
- [ ] Update Catalyst/Orb system prompts when created
---
## Related Tasks
- Task #109: MCP Logging in Trinity Console (moves logs off Pi)
- Task #111: Trinity Core Web MCP Connector (main implementation)
---
**Fire + Frost + Foundation = Where Love Builds Legacy** 💙🔥❄️