Repository navigation
Subagent empty tool allowlist is fail-open — child inherits parent's full tool surface (shell/spawn) #4452
Description
Part of the v0.58.7 → HEAD TinyAgents-migration audit (see parent issue).
Problem
Sub-agent tool exposure inverted from fail-closed to fail-open. Old subagent_runner/ops/tool_source.rs:53-107 (v0.58.7) denied any tool not in the allowlist — an empty allowlist meant deny-all. The new registration predicate at src/openhuman/tinyagents/mod.rs:1126 is allowed.is_empty() || allowed.contains(name) — an empty allowlist now registers every tool across tool_sets, which includes parent.all_tools: shell, file-write, spawn/delegate tools.
Reachable by:
- a custom agent TOML with
tools = [](ToolScope::Namedis user-deserializable,src/openhuman/agent/harness/definition.rs:621-629); - a
skill_filterthat matches zero tools; - a
namedlist whose entries are absent from the parent surface (silently resolves to empty).
Compounding factors: the spawn-tool strip at subagent_runner/ops/runner.rs:415 operates on allowed_indices only, so the "sub-agents must never spawn" invariant is bypassed too; and subagent turns pass tool_policy: None (ops/graph.rs:267), so registration is the only gate.
Failure scenario
A deliberately tool-less summarizer agent processing untrusted content (web page, email) silently gains shell + file-write + spawn — a prompt-injection privilege escalation.
Fix plan
- In
src/openhuman/tinyagents/mod.rs:1126, distinguish "no filter supplied" (None→ all tools) from "empty allowlist" (Some(empty)→ deny all). Change the plumbed type fromVec<String>/HashSet<String>toOption<HashSet<String>>end-to-end (subagent_runner/ops/runner.rs:690-698→assemble_turn_harness). - Make
ToolScope::Named([])and a zero-matchskill_filterproduceSome(empty)(deny-all), matching v0.58.7 semantics. Log a warn ([subagent] tool allowlist resolved empty — registering no tools) so misconfigured agents are diagnosable. - Re-assert the spawn-tool invariant at registration time (strip spawn/delegate names from whatever set is registered, not just from
allowed_indices). - Consider also passing a real
tool_policyon the subagent path instead ofNone(defense in depth).
Acceptance criteria
tools = []/ zero-match filters register zero tools; the subagent can still complete text-only turns.- No subagent configuration can implicitly inherit the parent's full tool surface.
- Spawn/delegate tools are never registered to a subagent regardless of allowlist content.
- Unit tests over the registration predicate for:
None,Some(empty),Some({named}), named-but-unresolvable; plus an e2e asserting atools = []agent has noshell.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
fix(agent): make subagent tool allowlist fail-closed (tinyhumansai#4452)
test(agent): cover image-aware token estimate + subagent spawn-strip
M3gA-Mind commentedon Jul 7, 2026
Already resolved by merged PR #4495 ("TinyAgents migration parity & bug fixes (#4451–#4469)") plus follow-up #4504 — the fix is present in
main. Closing as completed.fix(agent): hand sub-agents the durable registry's own specs
fix(agent): reconcile delegation tools without owning the tools Arc
fix(agent): reconcile delegation tools without owning the tools Arc\n…
fix(agent): hand sub-agents the durable registry's own specs\n\nRevie…