T05 · Unauthorized Access and Privilege Escalation
- Location
control.ts:58- Finding
Unscoped Emergency Flush Can Terminate Unrelated Process Sessions
- Content
View full analysis
Vulnerability Details
File Location:
control.ts:58-76
Vulnerability Type: Missing authorization and process-ownership validation
Risk Level: Hights // /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 throughprocess.list({})and passes every returned session identifier toprocess.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
- An attacker or compromised component gains the ability to invoke the exported
flush()function or a command handler exposing it as/flush. flush()callsprocess.list({}), enumerating every process session visible to the SDK caller.- The function iterates over the unfiltered session collection.
- Each session identifier is supplied to
process.kill(), without checking whether error-guard created or owns that session. - Unrelated workloads ...[truncated 716 chars]
- An attacker or compromised component gains the ability to invoke the exported
- Remediation
View remediation
Remediation Suggestions
- Record the process or session identifier returned whenever an error-guard worker is created.
- Maintain an explicit task-to-session ownership mapping in the control-plane registry.
- During
flush(), terminate only session identifiers recorded as owned by active error-guard tasks. - Revalidate ownership immediately before every termination to avoid stale-identifier and race-condition issues.
- Require an authenticated and authorized control-plane caller for destructive operations such as
/flushand/recover. - Maintain a denylist of protected control-plane and infrastructure sessions as defense in depth.
- Clear registry entries only after termination attempts have been recorded; preserve enough state to retry failed cleanup safely.
- Return an accurate structured result containing terminated, skipped, and failed session identifiers instead of unconditionally reporting success.
- Add tests confirming that unrelated sessions returned by the SDK are never passed to
process.kill().
