Skip to content

[security] fix(agent-to-agent): authorize create_agent actions#2383

Open
Hinotoi-agent wants to merge 1 commit into
nanocoai:mainfrom
Hinotoi-agent:fix/create-agent-source-authorization
Open

[security] fix(agent-to-agent): authorize create_agent actions#2383
Hinotoi-agent wants to merge 1 commit into
nanocoai:mainfrom
Hinotoi-agent:fix/create-agent-source-authorization

Conversation

@Hinotoi-agent
Copy link
Copy Markdown
Contributor

Summary

This PR hardens the host-side agent-to-agent management boundary for create_agent system actions.

It adds an authorization check before the host creates persistent agent groups or writes bidirectional agent_destinations ACL rows, and covers both denied and allowed paths with focused regression tests.

Security issues covered

Issue Impact Severity
Untrusted agent session can emit a forged create_agent system action Persistent agent group creation plus bidirectional agent-destination ACL mutation without an admin-owned source context High

Before this PR

  • The container-controlled messages_out database could contain kind: "system" messages with action: "create_agent".
  • handleCreateAgent() trusted that action and immediately created a new agent_groups row, initialized group filesystem state, and inserted bidirectional agent_destinations rows.
  • The comment in the container MCP tool said the host re-checks permission, but the host-side handler did not actually enforce an admin/main/trusted source check.
  • There was no regression coverage proving that member-only or child/untrusted source groups are denied.

After this PR

  • handleCreateAgent() now checks the source agent group before mutating host state.
  • A source group may create agents only when it is tied to a privileged operator context:
    • a scoped admin for that same agent group, or
    • a global owner/admin who also has an explicit membership row for that source group.
  • The explicit membership requirement prevents a compromised child/untrusted group from inheriting ambient global owner/admin authority just because such a user exists elsewhere in the deployment.
  • Regression tests now lock in:
    • member-only source groups are denied;
    • child groups are denied even when a global owner exists elsewhere;
    • owner-tied source groups still work;
    • scoped-admin source groups still work.

Why this matters

Agent containers control their outbound session database, so the presence or absence of an MCP tool in the container is not a sufficient security boundary. The trusted host must treat every outbound system action as potentially forged and re-check authorization at the point where central DB and host filesystem state are mutated.

Without this check, a less-trusted or compromised agent can create long-lived agent identities and routing ACLs, changing the topology of the deployment without an owner/admin decision.

Attack flow

Untrusted/compromised agent container
    -> writes { kind: "system", action: "create_agent" } to messages_out
        -> host delivery dispatches handleCreateAgent()
            -> host creates a persistent agent group and bidirectional ACL rows

Affected code

Issue Files
Missing host-side authorization for create_agent src/modules/agent-to-agent/create-agent.ts, src/modules/agent-to-agent/create-agent.test.ts

Root cause

Issue: untrusted agent session can create/manage new agent groups through create_agent

  • Direct cause: handleCreateAgent() created agent groups and destination rows without checking whether the source session's agent group was admin/owner-tied.
  • Boundary failure: the host relied on container/tool visibility comments even though the container-controlled outbound DB can forge system actions directly.

CVSS assessment

Issue CVSS v3.1 Vector
Untrusted create_agent system action mutates agent topology/ACLs 8.5 High CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:L

Rationale:

  • The attacker needs an existing untrusted/less-privileged agent execution context, so privileges are Low rather than None.
  • The resulting impact crosses from that agent context into trusted host-managed central DB state, group filesystem initialization, and cross-agent routing ACLs.
  • The proof does not claim direct host command execution or secret disclosure, so the assessment stays at High rather than Critical.

Safe reproduction steps

  1. Create a non-admin/member-only source agent group and active session in a local test database.

  2. Call the real handleCreateAgent() with a forged system-action payload:

    {
      "action": "create_agent",
      "requestId": "poc",
      "name": "Evil Child"
    }
  3. On vulnerable code, observe that a new child agent_groups row is created and bidirectional agent_destinations rows are inserted.

  4. With this PR, the same source is denied before group creation, filesystem initialization, or destination ACL mutation.

The new regression test denies create_agent from a member-only source agent without mutating groups or destinations covers this behavior directly.

Expected vulnerable behavior

On vulnerable code, a non-main/untrusted source agent can create a persistent child agent and receive a new destination name for it. The child also receives a parent destination back to the source group, creating bidirectional agent-to-agent routing without an owner/admin authorization point.

Changes in this PR

  • Adds a host-side canSourceCreateAgent() guard in handleCreateAgent().
  • Denies unauthorized source groups before collision checks, folder creation, DB inserts, filesystem initialization, or destination projection.
  • Allows the intended trusted paths for:
    • source groups explicitly tied to a global owner/admin through membership; and
    • source groups with a scoped admin role.
  • Adds focused Vitest coverage for denied and allowed paths.

Files changed

Category Files What changed
Authorization src/modules/agent-to-agent/create-agent.ts Adds host-side authorization before create_agent can mutate agent groups or destinations.
Tests src/modules/agent-to-agent/create-agent.test.ts Adds regression coverage for untrusted/member-only denial, child-group denial, owner-tied allow, and scoped-admin allow.

Maintainer impact

  • The patch is intentionally narrow and only changes the create_agent delivery-action path.
  • Existing owner/admin-managed source groups can still create companion agents.
  • Member-only and child/untrusted groups now fail closed with a notification instead of mutating persistent topology.
  • No channel adapter, provider, scheduling, or generic delivery behavior is changed.

Fix rationale

The durable boundary is the host-side mutation point, not the container-side tool registry. A compromised container can write outbound system messages directly, so the handler that creates agent_groups and agent_destinations must enforce the authorization decision immediately before those writes.

Requiring explicit membership for global owner/admin authority keeps normal first-agent/owner workflows working while avoiding ambient privilege inheritance for unrelated child groups.

Type of change

  • Security fix
  • Tests
  • Documentation update
  • Refactor with no behavior change

Test plan

  • Focused create-agent authorization regression tests.
  • Adjacent agent-to-agent routing tests.
  • TypeScript typecheck.
  • Full Vitest suite.
  • ESLint on touched files.
  • Whitespace diff check.
  • Local test-artifact cleanup check for NanoClaw temp/config paths.

Executed with:

corepack pnpm exec vitest run src/modules/agent-to-agent/create-agent.test.ts --reporter=verbose
corepack pnpm exec prettier --write src/modules/agent-to-agent/create-agent.ts src/modules/agent-to-agent/create-agent.test.ts
corepack pnpm exec vitest run src/modules/agent-to-agent/create-agent.test.ts src/modules/agent-to-agent/agent-route.test.ts --reporter=verbose
corepack pnpm run typecheck
git diff --check
corepack pnpm test -- --run
corepack pnpm exec eslint src/modules/agent-to-agent/create-agent.ts src/modules/agent-to-agent/create-agent.test.ts

Token usage

  • discovery tokens: partial/unknown
  • validation tokens: partial/unknown
  • duplicate-check tokens: partial/unknown
  • PR/writeup tokens: partial/unknown
  • total tokens: partial/unknown
  • notes: This PR is backed by local code review, a focused pre-patch proof harness, duplicate checks against visible GitHub issues/PRs/advisories, and the validation commands listed above. Exact token telemetry is not available in this local PR workflow.

Disclosure notes

  • This PR is bounded to the create_agent host-side authorization gap.
  • It does not claim direct host command execution, credential disclosure, or a container escape.
  • The fix assumes outbound system actions are container-controlled and therefore must be authorized by the host before central DB or filesystem mutation.
  • No unrelated files were changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant