Actor Fallback to Agent Creator (Confused Deputy)¶
Evidence Level: F (directly proven by source code)
Analysis Baseline:4f843556
TL;DR¶
When context.actor_user_id is None (anonymous/unauthenticated/delegated execution), the system silently falls back to agent.creator_id (typically an admin), creating a Confused Deputy vulnerability.
1. Fallback Point 1: File Deletion¶
backend/app/services/agent_runtime/tool_step_service.py:494:
This fallback is used for permission decisions on delete_file and GROUP_DELETE_WORKSPACE_FILE. When actor_user_id is None, file deletion executes with the identity of the Agent's creator (typically an admin).
2. Fallback Point 2: General Tool Execution¶
tool_step_service.py:1879:
raw_result = await self._tool_executor(
tool_name,
arguments,
agent.id,
context.actor_user_id and uuid.UUID(context.actor_user_id)
or agent.creator_id,
context.session_id or "",
)
Same pattern—when actor_user_id is None, falls back to agent.creator_id.
3. actor_user_id Can Be None¶
backend/app/services/agent_runtime/state.py:214:
The type of actor_user_id is str | None—the system is designed to allow it to be None.
4. Trigger Scenarios¶
Scenarios where actor_user_id may be None include:
- Delegated execution (delegated run): A2A delegation, OpenClaw gateway messages
- Group chat context: Agent-to-Agent
@calls in group chats, where the original user context may be lost - Scheduled tasks/triggers: Scheduler-triggered execution has no human user context
- Anonymous execution: Runs invoked directly via API
5. Confused Deputy Attack Chain¶
Ordinary employee Jerry @-mentions an Agent created by admin Tom in a group chat
→ Agent processes the group message; context.actor_user_id may be None
→ Tool execution falls back to agent.creator_id = Tom (admin)
→ Jerry performs file operations/tool calls with Tom's admin privileges
6. Relationship to AI Coding¶
This or fallback is the classic "just make it work" development pattern:
- A developer encounters a failure when
actor_user_idisNoneon some path - They add
or str(agent.creator_id)as a "fallback" to make it work - They don't realize this grants unauthorized users admin-level privileges
- The two fallback points (line 494 and line 1879) were implemented independently, suggesting the same problem was patched twice, each time in the same way