You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Native (vendor-owns-loop) backends -- handles_tools_internally? == true,
e.g. Backend.ClaudeCode / Backend.Cursor -- run their own tool loop and
execute Raxol Actions out-of-process over MCP (native_react/1 in Raxol.Agent.Stream, tools injected via Harness.McpToolConfig). On that path
the framework cannot thread run context into tool execution:
context[:tool_authorizer] (the ToolPolicy that denies sensitive: true
fund-mover Actions)
context[:tool_call_hooks] (the ToolCall.Hook pipeline)
app flags such as the cron :in_cron recursion guard and :owner scoping
read by Actions.Cronjob
All of these are silently dropped, because the spawned MCP server that runs the
tool receives none of the caller's BEAM-process context. Any context-based
security control is therefore unenforced when a native backend is in use.
This does not bite today: no sensitive/context-guarded Action is wired
into any native react call, Actions.Cronjob is unwired everywhere, and there
is no MCP server that reads RAXOL_MCP_TOOLS_FILE to execute these tools. It is
a latent trap that springs the moment any of that is wired.
Interim mitigation already in place
Raxol.Agent.Scheduler.Fire fails closed for the cron fire path: when the
resolved backend is native (Stream.native_tool_loop?/1), it withholds Actions.Cronjob from the injected toolset entirely (see PR from #494
follow-up). This is a point-fix scoped to cron fires.
What the general fix must cover
Owner-scoping IDOR over the native path, not just the recursion guard.
Even outside a fire (a normal interactive session on a native backend),
cronjob list/remove would run without context[:owner] -> cross-owner
read/delete. This is the same IDOR class the Cron scheduler: Raxol.Agent.Cron (parse-once, per-agent GenServer) #494 review caught on the
framework path; the fix must reach the native path too.
Generality -- replace the hardcoded Actions.Cronjob reference in Fire.guard_context_actions/2 with a declarative marker (an Action opting
into "requires in-process context enforcement"), so authorizer/hooks/owner/
in_cron-dependent Actions are withheld from any native toolset by
construction, and a new such Action can't silently regress.
Enforcement, not just withholding -- ideally carry a minimal, safe
projection of context (owner, in_cron, authorizer verdicts) into the MCP
tool config so the out-of-process server can reconstruct and enforce it,
rather than dropping capability. This is the larger design question.
Scope
Research item -- design first (option 3 from the #494 follow-up triage). Low
priority: no live exposure until native tool derivation is actually wired for a
context-guarded Action. Tracks alongside #494.
Summary (research / low priority)
Native (vendor-owns-loop) backends --
handles_tools_internally? == true,e.g.
Backend.ClaudeCode/Backend.Cursor-- run their own tool loop andexecute Raxol Actions out-of-process over MCP (
native_react/1inRaxol.Agent.Stream, tools injected viaHarness.McpToolConfig). On that paththe framework cannot thread run context into tool execution:
context[:tool_authorizer](theToolPolicythat deniessensitive: truefund-mover Actions)
context[:tool_call_hooks](theToolCall.Hookpipeline):in_cronrecursion guard and:ownerscopingread by
Actions.CronjobAll of these are silently dropped, because the spawned MCP server that runs the
tool receives none of the caller's BEAM-process context. Any context-based
security control is therefore unenforced when a native backend is in use.
This does not bite today: no
sensitive/context-guarded Action is wiredinto any native react call,
Actions.Cronjobis unwired everywhere, and thereis no MCP server that reads
RAXOL_MCP_TOOLS_FILEto execute these tools. It isa latent trap that springs the moment any of that is wired.
Interim mitigation already in place
Raxol.Agent.Scheduler.Firefails closed for the cron fire path: when theresolved backend is native (
Stream.native_tool_loop?/1), it withholdsActions.Cronjobfrom the injected toolset entirely (see PR from #494follow-up). This is a point-fix scoped to cron fires.
What the general fix must cover
Even outside a fire (a normal interactive session on a native backend),
cronjob
list/removewould run withoutcontext[:owner]-> cross-ownerread/delete. This is the same IDOR class the Cron scheduler: Raxol.Agent.Cron (parse-once, per-agent GenServer) #494 review caught on the
framework path; the fix must reach the native path too.
Actions.Cronjobreference inFire.guard_context_actions/2with a declarative marker (an Action optinginto "requires in-process context enforcement"), so authorizer/hooks/owner/
in_cron-dependent Actions are withheld from any native toolset by
construction, and a new such Action can't silently regress.
projection of context (owner, in_cron, authorizer verdicts) into the MCP
tool config so the out-of-process server can reconstruct and enforce it,
rather than dropping capability. This is the larger design question.
Scope
Research item -- design first (option 3 from the #494 follow-up triage). Low
priority: no live exposure until native tool derivation is actually wired for a
context-guarded Action. Tracks alongside #494.