fix: propagate session permissions correctly to sub-sessions#3542
fix: propagate session permissions correctly to sub-sessions#3542Piyush0049 wants to merge 7 commits into
Conversation
Sub-agents now inherit the exact Allow, Ask, and Deny rules from the parent session instead of bypassing them. This resolves a known prompt-injection loophole for background agents. Signed-off-by: piyush0049 <piyushjoshi81204@gmail.com>
|
Note: Learning from previous PRs, I also added a unit test to verify that this behavior works correctly and stays fixed in the future. You can run the test locally using this command: |
Sayt-0
left a comment
There was a problem hiding this comment.
Thanks for tackling this. Inheriting the parent permissions in newSubSession is the right insertion point. Two points look blocking before this can land, plus a test gap; details are inline.
| area | concern |
|---|---|
| correctness | background agents run with ToolsApproved: true, and Decide short-circuits on the yolo flag before any checker runs, so the inherited Allow/Ask/Deny rules are never consulted on that path (the exact case the removed TODO described) |
| isolation | the parent PermissionsConfig pointer is shared with the child instead of cloned, unlike every other call site |
| tests | the new test asserts field copying only, not dispatch behaviour |
| opts = append(opts, session.WithAgentName(cfg.AgentName)) | ||
| } | ||
| if parent.Permissions != nil { | ||
| opts = append(opts, session.WithPermissions(parent.Permissions)) |
There was a problem hiding this comment.
This shares the parent's *PermissionsConfig (and its underlying slices) with the child instead of cloning it. Every other call site clones through clonePermissionsConfig (session.Clone, copySessionMetadata in branch.go, store.go). The aliasing is not benign: on the interactive transfer_task path, handleResume's ResumeTypeApproveTool case appends to sess.Permissions.Allow, so a child approving a tool would mutate the parent's permissions (and append to a shared slice). Suggest cloning here, for example by exposing the existing clonePermissionsConfig helper and passing session.WithPermissions(clone).
| @@ -482,10 +485,6 @@ func (r *LocalRuntime) CurrentAgentSubAgentNames() []string { | |||
| // authorises all tool calls made by the sub-agent when they approve | |||
| // run_background_agent. Callers should be aware that prompt injection in | |||
| // the sub-agent's context could exploit this gate-bypass. | |||
There was a problem hiding this comment.
Removing this TODO looks premature. RunAgent (background agents) sets ToolsApproved: true, and Decide (pkg/runtime/toolexec/permissions.go) returns Allow on the yolo flag before evaluating any checker. So the newly inherited parent Deny/Ask rules are never consulted for a background sub-session, which is precisely the bypass this TODO called out ("rather than a single shared ToolsApproved flag"). The warning just above ("could exploit this gate-bypass") still holds, so it now contradicts the TODO removal. Options: keep the TODO, or make Deny/ForceAsk win over the yolo flag in Decide (at least for an inherited session-level Deny) and cover it with a test.
| require.NotNil(t, s.Permissions) | ||
| assert.Equal(t, perms.Allow, s.Permissions.Allow) | ||
| assert.Equal(t, perms.Deny, s.Permissions.Deny) | ||
| assert.Equal(t, perms.Ask, s.Permissions.Ask) |
There was a problem hiding this comment.
This checks field copying but not that inheritance changes dispatch behaviour. Consider driving the approval path instead: a parent Deny of write_* should still deny in the child, and in particular the background-agent case (ToolsApproved: true) where the inherited Deny currently has no effect. That case would document the gap flagged in agent_delegation.go.
- Deep clone parent permissions into the child session to prevent aliasing - Re-order yolo check in Decide to ensure inherited Deny/ForceAsk overrides ToolsApproved: true - Enhance TestSubSessionInheritsPermissions to assert actual dispatch behavior Signed-off-by: piyush0049 <piyushjoshi81204@gmail.com>
|
@Sayt-0 Thank you for the review, I read it and have pushed an update addressing all three of your points:
All tests are passing locally. Do let me know if any change is required please. |
Signed-off-by: piyush0049 <piyushjoshi81204@gmail.com>
|
I just pushed a quick follow-up commit to fix the CI failures. |
|
HI @Piyush0049 can you resolve the conflicts ? ping me when its done |
|
Sayt-0 Sure |
…sions # Conflicts: # pkg/runtime/agent_delegation.go # pkg/runtime/agent_delegation_test.go
…sions # Conflicts: # pkg/runtime/toolexec/dispatcher.go
|
Sayt-0 I have resolved the merge conflicts. Please do let me know if any changes are required. |
Signed-off-by: piyush0049 <piyushjoshi81204@gmail.com>
|
I've pushed a commit to fix the CI timeout in The Side Note: While testing locally on Windows, I noticed a few pre-existing issues in |
|
The |
What this PR does / why we need it:
This PR resolves an open
TODOregarding permission scoping during agent delegation.Previously, when a parent session delegated a task to a sub-session (such as a background agent), the parent's explicit
PermissionsConfig(Allow/Deny/Ask rules) was not inherited by the child session. Because background tasks often run withToolsApproved: true, this created a potential gate-bypass where a sub-agent could execute tools that the user explicitly denied in the parent session.Now that the runtime fully supports per-session permission scoping, this PR updates
newSubSessionto correctly inherit and append the parent's permissions.Which issue(s) this PR fixes:
Fixes an inline
TODOinpkg/runtime/agent_delegation.go.Special notes for your reviewer:
TestSubSessionInheritsPermissionstopkg/runtime/agent_delegation_test.goto explicitly verify that the Allow, Ask, and Deny rules are correctly propagated to child agents.