security: prevent self-approval in exec.approval.resolve handler
A prompt-injected agent could call exec.approval.request to register a dangerous command and then immediately call exec.approval.resolve with "allow-once" to execute it, bypassing human-in-the-loop oversight. The ExecApprovalRecord already captures requestedByConnId on the request side, but the resolve handler never checked it, leaving the field unused despite the aspirational comment "Used to prevent other clients from replaying an approval id". This commit enforces the separation: if the WebSocket connection that created the approval request is the same connection attempting to resolve it, the resolve is rejected with INVALID_REQUEST. Attack scenario blocked: 1. Malicious/compromised agent sends exec.approval.request (connId=A) 2. Same agent immediately sends exec.approval.resolve allow-once (connId=A) 3. Previously: command executed without human review 4. Now: INVALID_REQUEST "requester cannot approve their own exec request" Fixes: CRITICAL-02 (exec approval self-approval / cross-client hijacking)
This commit is contained in:
parent
1cf544ffbc
commit
fb35d46f9d
@ -312,6 +312,24 @@ export function createExecApprovalHandlers(
|
||||
}
|
||||
const approvalId = resolvedId.id;
|
||||
const snapshot = manager.getSnapshot(approvalId);
|
||||
// Security: prevent self-approval — the connection that submitted the request
|
||||
// cannot also resolve it. This blocks prompt-injected agents from immediately
|
||||
// approving their own dangerous command requests without human oversight.
|
||||
if (
|
||||
snapshot?.requestedByConnId != null &&
|
||||
client?.connId != null &&
|
||||
client.connId === snapshot.requestedByConnId
|
||||
) {
|
||||
respond(
|
||||
false,
|
||||
undefined,
|
||||
errorShape(
|
||||
ErrorCodes.INVALID_REQUEST,
|
||||
"requester cannot approve their own exec request",
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const resolvedBy = client?.connect?.client?.displayName ?? client?.connect?.client?.id;
|
||||
const ok = manager.resolve(approvalId, decision, resolvedBy ?? null);
|
||||
if (!ok) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user