T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- control.ts:58
- Finding
- Unscoped Emergency Flush Can Terminate Unrelated Process Sessions## Vulnerability Details **File Location**: `control.ts:58-76` **Vulnerability Type**: Missing authorization and process-ownership validation **Risk Level**: High ```ts // /flush: emergency stop export async function flush() { // Mark tasks as cancelled registry.forEach(t => t.state = "cancelled"); registry.clear(); // Kill active exec sessions (best-effort) try { const procs = await process.list({}); for (const p of procs.sessions || []) { await process.kill({ sessionId: p.sessionId }); } } catch (e) { // Swallow errors: flush must always respond } return { ok: true, message: "All tasks cancelled, exec sessions killed, registry cleared", ts: now() }; } ``` ### Technical Analysis The exported `flush()` operation obtains the complete set of process sessions visible through `process.list({})` and passes every returned session identifier to `process.kill()`. It does not verify that a process belongs to a task created or managed by this skill. No caller authorization, process ownership check, task-to-session mapping, protected-session allowlist, or scope restriction is applied before termination. Consequently, the operation crosses the expected least-privilege boundary between error-guard workers and unrelated workloads. The catch block also suppresses every termination error, while the function unconditionally returns `ok: true`. This can conceal partial cleanup and make it difficult to determine which sessions were actually terminated. ### Attack Path 1. An attacker or compromised component gains the ability to invoke the exported `flush()` function or a command handler exposing it as `/flush`. 2. `flush()` calls `process.list({})`, enumerating every process session visible to the SDK caller. 3. The function iterates over the unfiltered session collection. 4. Each session identifier is supplied to `process.kill()`, without checking whether error-guard created or owns that session. 5. Unrelated workloads ...[truncated 716 chars]
- Remediation
- ## Remediation Suggestions 1. Record the process or session identifier returned whenever an error-guard worker is created. 2. Maintain an explicit task-to-session ownership mapping in the control-plane registry. 3. During `flush()`, terminate only session identifiers recorded as owned by active error-guard tasks. 4. Revalidate ownership immediately before every termination to avoid stale-identifier and race-condition issues. 5. Require an authenticated and authorized control-plane caller for destructive operations such as `/flush` and `/recover`. 6. Maintain a denylist of protected control-plane and infrastructure sessions as defense in depth. 7. Clear registry entries only after termination attempts have been recorded; preserve enough state to retry failed cleanup safely. 8. Return an accurate structured result containing terminated, skipped, and failed session identifiers instead of unconditionally reporting success. 9. Add tests confirming that unrelated sessions returned by the SDK are never passed to `process.kill()`.
