T05 · Unauthorized Access and Privilege Escalation
- Location
control.ts:58- Finding
Unscoped Flush Operation Can Terminate Unrelated Execution Sessions
- Content
View full analysis
Vulnerability Details
File Location:
control.ts, lines 58–76
Vulnerability Type: Missing ownership validation for destructive session-management operations
Risk Level: HighVulnerable Code
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()function obtains the global execution-session list and terminates every session returned by the SDK. It does not verify that a session:- Was created by this skill;
- Corresponds to a task in the local registry;
- Is owned by the requesting user or agent; or
- Is otherwise within the legitimate scope of the emergency-stop operation.
The task registry only records task metadata and does not associate task IDs with spawned execution-session IDs. Consequently,
flush()cannot distinguish skill-owned workers from unrelated workloads.The issue also affects
recover()atcontrol.tslines 81–88 because that function invokesflush()directly. Whether an external actor can exploit this behavior depends on how the host application authorizes access to these exported operations, but the destructive implementation itself lacks a least-privilege boundary.Attack Path
- An actor, integration, or automation with access to the exported control operation invokes
flush()orrecover(). flush()clears the local task registry.- It calls
process.list({})and receives all execution sessions visible to the skill's SDK context. - It iterates over the ret ...[truncated 726 chars]
- Remediation
View remediation
Remediation Suggestions
- Capture the session identifier returned by
sessions_spawn()and associate it with the corresponding task ID in the registry. - Maintain an explicit allowlist of sessions created and owned by this skill.
- Change
flush()to terminate only sessions in that allowlist instead of enumerating and killing all visible sessions. - Before termination, validate task ownership, session ownership, and the caller's authorization for destructive operations.
- Separate global administrative recovery from ordinary skill-level recovery. If global termination is genuinely required, expose it only through a privileged, explicitly confirmed administrative interface.
- Persist sufficient ownership metadata safely if recovery must work across restarts.
- Return partial-failure details rather than silently swallowing every termination error, while avoiding disclosure of sensitive session metadata.
- Add tests proving that unrelated sessions remain active after
flush()andrecover()are invoked.
- Capture the session identifier returned by
