Skip to content

SSE handler: race in confirm_tool_execution can drop an early approval #792

@kovtcharov

Description

@kovtcharov

Summary

SSEOutputHandler.confirm_tool_execution resets _confirm_result = False and replaces _confirm_event on entry. If the HTTP handler calls resolve_tool_confirmation(True) before confirm_tool_execution runs its reset, the approval is clobbered.

Location

src/gaia/ui/sse_handler.py:690-745

def confirm_tool_execution(self, ...):
    confirm_id = str(uuid.uuid4())
    self._confirm_event = threading.Event()     # ← overwrites any event resolve_tool_confirmation created
    self._confirm_result = False                # ← discards any prior approval
    ...

def resolve_tool_confirmation(self, approved: bool) -> bool:
    if self._confirm_event is None:
        self._confirm_event = threading.Event() # ← creates orphan event
    self._confirm_result = approved
    self._confirm_event.set()
    return True

Reachability

Low. The intended order is:

  1. confirm_tool_execution emits permission_request SSE event.
  2. Frontend renders modal, user clicks.
  3. resolve_tool_confirmation is called.

So step 3 can only realistically run after step 1 has done its resets. The bug needs an out-of-order HTTP call (e.g., a replay or a speculative client) to manifest.

Suggested Fix

Either (a) create the event in __init__ and never replace it, only .clear() it; or (b) make resolve_tool_confirmation a no-op when _confirm_event is None (drop the event-creation branch).

(b) is one line:

def resolve_tool_confirmation(self, approved: bool) -> bool:
    if self._confirm_event is None:
        return False   # no pending request
    self._confirm_result = approved
    self._confirm_event.set()
    return True

The HTTP endpoint at src/gaia/ui/routers/chat.py:180-196 already 404s on missing handler; this just tightens the internal contract.

Impact

  • Low severity — requires an unusual client/proxy replay.
  • Fix is trivial and pure cleanup; safe to bundle with other SSE hardening.

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-uiAgent UI changesbugSomething isn't workingrobustnessReliability, error handling, and hardening

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions