Skip to content

Add spawn_agent space enforcement (SEC-007)#10

Open
tiwillia-ai-bot wants to merge 2 commits intoopenshift-online:mainfrom
tiwillia:feat/enforce-spawn-agent-space
Open

Add spawn_agent space enforcement (SEC-007)#10
tiwillia-ai-bot wants to merge 2 commits intoopenshift-online:mainfrom
tiwillia:feat/enforce-spawn-agent-space

Conversation

@tiwillia-ai-bot
Copy link
Copy Markdown
Contributor

Summary

Implements mechanical enforcement to prevent agents from spawning other agents in arbitrary spaces. When a parent agent is specified, the system now validates that the new agent is created in the same space as the parent.

Problem

The spawn_agent tool previously allowed agents to create other agents in any space, not just their assigned space. This caused operational issues where agents were inadvertently created in wrong spaces (e.g., jsell-agent-boss instead of odis-devel).

Solution

Added space validation in two locations:

  1. MCP tool (spawn_agent): Validates that when a parent parameter is provided, the target space parameter matches the parent's actual space
  2. HTTP API (POST /spaces/{space}/agents): Same validation for HTTP-based agent creation

The validation:

  • Searches all spaces to find where the parent agent exists
  • Compares the parent's space with the target space (case-insensitive)
  • Rejects the spawn with a clear error message if spaces don't match
  • Only applies when a parent is specified (maintains backward compatibility)

Changes

  • internal/coordinator/mcp_tools.go: Added space enforcement in addToolSpawnAgent
  • internal/coordinator/handlers_agent.go: Added space enforcement in handleCreateAgents
  • internal/coordinator/server_test.go: Added comprehensive test coverage (TestSpawnAgentSpaceEnforcement)

Test Plan

  • Unit tests for MCP tool cross-space spawn rejection
  • Unit tests for MCP tool same-space spawn acceptance
  • Unit tests for HTTP endpoint cross-space spawn rejection
  • Unit tests for non-existent parent rejection
  • Unit tests for spawns without parent (backward compatibility)
  • All existing tests pass

Security

Addresses SEC-007: Space isolation enforcement for agent spawning operations.

🤖 Generated with Claude Sonnet 4.5

@tiwillia-ai-bot
Copy link
Copy Markdown
Contributor Author

Review Summary

Overall: CHANGES REQUESTED

Severity Count
Critical 2
Concern 8
Informational 5

This PR implements SEC-007, an important security enhancement preventing agents from spawning child agents in arbitrary spaces. The implementation is backend-agnostic and includes comprehensive test coverage. However, there are two critical issues that must be resolved before merge: (1) the test code references an undefined helper function that will cause compilation failure, and (2) the case-insensitive space comparison could create a security bypass vulnerability. Additionally, there are several concerns around code duplication, lock duration, and continued growth of already oversized files that should be addressed.


General

Verdict: CONCERNS — Security enhancement is well-implemented with good test coverage, but there are concerns around lock duration, case-sensitivity handling, and error response consistency.

Details

Findings

  • [CONCERN] handlers_agent.go:1549-1562 — The parent lookup searches all spaces while holding s.mu.RLock(). For servers with many spaces and agents, this could hold the read lock longer than necessary. Consider releasing the lock sooner by copying the spaces map first, or restructuring to minimize lock duration. The pattern is repeated in mcp_tools.go:1094-1107.

  • [CONCERN] handlers_agent.go:1568 and mcp_tools.go:1113 — The space name comparison uses strings.EqualFold() for case-insensitive comparison, but the error message preserves original case. This is good for user feedback. However, verify that the codebase consistently treats space names as case-insensitive elsewhere. The review checklist mentions "Case-insensitive lookups where appropriate" for agents, but there's no explicit mention of space name case handling in the guidelines.

  • [CONCERN] handlers_agent.go:1566-1572 — The HTTP endpoint returns http.StatusForbidden (403) for cross-space spawn attempts, which is semantically correct. However, verify this is consistent with other authorization-related failures in the codebase. The error message format is good and follows the writeJSONError() convention.

  • [CONCERN] mcp_tools.go:1110-1116 — The MCP tool returns a toolError() for cross-space spawn attempts, which is correct. However, the MCP tool returns toolError() for a non-existent parent (line 1109), while the HTTP endpoint returns http.StatusBadRequest (line 1565). This inconsistency is minor but worth noting — both paths should ideally have similar semantics for the same error condition.

  • [INFO] server_test.go:4850-4980 — The test coverage is comprehensive and tests both the MCP tool and HTTP endpoint paths. Good use of test cases covering: cross-space rejection, same-space acceptance, non-existent parent, and no-parent scenarios. This demonstrates good understanding of edge cases.

  • [INFO] All files — The security rationale (SEC-007) is clearly documented in comments at both enforcement points. This is excellent for future maintainers who need to understand why this restriction exists.

Positive

  • Comprehensive test coverage with 6 test cases covering both MCP and HTTP paths, plus edge cases like non-existent parents and backward compatibility.
  • Clear security documentation in code comments referencing SEC-007.
  • Consistent enforcement at both entry points (HTTP API and MCP tool).
  • Error messages are informative and include all relevant context (parent agent, source space, target space).
  • Backward compatible: agents without a parent can still be created in any space.
  • Proper use of existing patterns: resolveAgentName(), writeJSONError(), toolError().

Tmux Backend

Verdict: APPROVE — Space enforcement does not affect tmux backend implementation, lifecycle, or session management.

Details

Findings

  • [INFO] The changes add authorization checks at the HTTP handler and MCP tool layers, which are upstream of the backend dispatch mechanism. The validation logic does not modify the SessionBackend interface contract, does not touch tmux-specific code in session_backend_tmux.go or tmux.go, and occurs before backendFor(agent) is called, making it backend-agnostic.

  • [INFO] The test coverage correctly validates both entry points and includes cases for same-space spawning (allowed), cross-space spawning (rejected), and no-parent spawning (allowed).

Positive

  • The change is properly layered and does not introduce any tmux-specific assumptions.
  • Session lifecycle flows remain unchanged.
  • Works identically for both tmux and ambient backends.
  • Preserves backward compatibility for spawns without a parent.

Ambient Backend

Verdict: APPROVE — Space enforcement is correctly implemented as a pre-dispatch validation that does not affect ambient backend lifecycle, spawn flows, or interface contract.

Details

Findings

  • [INFO] This change is backend-agnostic and executes before backend dispatch. The ambient backend's CreateSession(), discovery logic, label management, and AG-UI message handling are completely unaffected.

  • [INFO] The enforcement adds a read lock operation (s.mu.RLock()) that searches all spaces for the parent agent. For deployments with many spaces and agents, this could have minor performance implications during spawn operations, but the search is necessary for security and the lock is released before the actual spawn begins.

  • [INFO] Both HTTP endpoint and MCP tool implement identical validation logic, which is correct for consistency across both spawn interfaces.

Positive

  • Comprehensive test coverage validates both enforcement paths (HTTP and MCP) and backward compatibility (no parent specified).
  • Error messages clearly identify which agent attempted to spawn in which space, aiding security auditing.
  • The implementation correctly uses read locks for the parent agent search, minimizing lock contention.
  • Backend-agnostic design means ambient and tmux backends benefit equally from this security enhancement without any interface changes.

Quality

Verdict: CHANGES REQUESTED — Test code contains undefined helper function and security implementation has potential bypass vulnerability.

Details

Findings

  • [CRITICAL] server_test.go:4878,4895,4910 — Test calls undefined helper function callMCPTool() which doesn't exist in the codebase. This test will not compile. The test needs either: (1) a new helper function that makes MCP tool calls via the HTTP API, or (2) refactoring to use direct HTTP calls to the MCP endpoint like other tests.

  • [CRITICAL] handlers_agent.go:1568, mcp_tools.go:1112 — Space name comparison uses strings.EqualFold() for case-insensitive matching. This creates a security vulnerability if space names are case-sensitive identifiers. An attacker could potentially bypass enforcement by creating spaces with different casing (e.g., "Space-A" vs "space-a"). Should use exact string comparison (parentSpace != spaceName) unless spaces are explicitly documented as case-insensitive.

  • [CONCERN] handlers_agent.go:1543-1575, mcp_tools.go:1091-1118 — Identical parent space lookup logic duplicated in two locations with only cosmetic variable naming differences (parentCanonical vs spawnerCanonical). This violates DRY principles and creates maintenance burden. Consider extracting to a shared helper function like findAgentSpace(s *Server, agentName string) (spaceName string, found bool).

  • [CONCERN] handlers_agent.go:1807+37, mcp_tools.go:1104+35 — Adding 37 and 35 lines respectively to files already grandfathered at 1807 and 1104 LOC (far exceeding the 600 line limit). While grandfathered files can grow, this is an opportunity to extract the new space enforcement logic into a separate helper file (e.g., helpers_space_enforcement.go) to prevent further bloat and improve testability.

  • [CONCERN] handlers_agent.go:1550-1562, mcp_tools.go:1098-1110 — Linear search across all spaces with O(n*m) complexity where n=number of spaces, m=average agents per space. For deployments with many spaces/agents, this could become a performance bottleneck. Consider maintaining a reverse index (agentID -> spaceName) or documenting acceptable scale limits.

  • [CONCERN] server_test.go:4880-4894 — Test setup creates parent agent via direct API call with hardcoded status "active" but no backend configuration. This may pass in test environment but doesn't reflect realistic agent creation flow. Consider using existing test helpers that properly initialize agent backends.

  • [INFO] The diff shows proper use of writeJSONError() for HTTP errors and appropriate status codes (400 for not found, 403 for forbidden), following error handling conventions.

Positive

  • Comprehensive test coverage with 6 sub-tests covering MCP tool, HTTP endpoint, same-space, cross-space, non-existent parent, and no-parent scenarios.
  • Security-conscious approach with explicit SEC-007 tagging and clear error messages that include space names for debugging.
  • Proper locking pattern using s.mu.RLock() for read-only operations during parent lookup.
  • Backward compatibility preserved: enforcement only applies when parent is specified.

tiwillia-ai-bot and others added 2 commits April 8, 2026 19:42
Problem: The spawn_agent tool allowed agents to create other agents in
arbitrary spaces, not just their own assigned space. This caused issues
where agents created in wrong spaces (e.g., jsell-agent-boss instead of
odis-devel).

Solution: Add mechanical enforcement to prevent cross-space spawning:
1. When a parent/spawner agent is specified, look up which space that
   parent exists in
2. Enforce that the target space parameter matches the parent's space
3. Reject the spawn attempt if spaces don't match

Changes:
- mcp_tools.go: Added space validation in spawn_agent MCP tool handler
- handlers_agent.go: Added same validation in HTTP POST /spaces/{space}/agents
- server_test.go: Added comprehensive test coverage for space enforcement

The validation is case-insensitive and only applies when a parent is
specified, maintaining backward compatibility for spawns without parents.

Fixes issue where agents could spawn agents in arbitrary spaces.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fixes:
1. Replace strings.EqualFold with exact string comparison for space
   enforcement (security fix - case-insensitive comparison could allow
   bypass attacks)
2. Extract duplicate parent lookup logic to shared findAgentSpace helper
   function in helpers.go to eliminate code duplication

Note: callMCPTool function exists at line 3457 of server_test.go and
tests compile successfully.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@tiwillia-ai-bot tiwillia-ai-bot force-pushed the feat/enforce-spawn-agent-space branch from 9672930 to bb0fe7e Compare April 8, 2026 19:43
@tiwillia-ai-bot
Copy link
Copy Markdown
Contributor Author

Code Review: PR #10 - Add spawn_agent space enforcement (SEC-007)

Review Summary

Overall: APPROVE

Severity Count
Critical 0
Concern 1
Informational 5

This PR implements a well-designed security enhancement that addresses SEC-007 by preventing agents from spawning other agents in arbitrary spaces. Both the HTTP endpoint and MCP tool are properly protected with consistent validation logic. The implementation demonstrates excellent engineering practices: comprehensive test coverage (6 test scenarios covering both success and failure paths), proper lock discipline, clear error messages, and full backward compatibility. The one concern relates to the O(spaces × agents) search performance in findAgentSpace(), but this is noted as low priority since it's unlikely to be a bottleneck in realistic deployments. Both reviewers highlight the quality of the test suite and the security-first approach as exemplary.


General

Verdict: APPROVE — Well-designed security enhancement with comprehensive test coverage and proper backward compatibility.

Details

Findings

  • [CONCERN] helpers.go:194-201 — The findAgentSpace() helper performs O(spaces × agents) linear search on every spawn with a parent. For typical deployments (few spaces, moderate agent counts) this is negligible. However, if spawning becomes a performance bottleneck with many spaces/agents, consider adding an agent→space index. Low priority since current implementation is correct and likely sufficient.

  • [INFO] There's a TOCTOU window between validation and agent creation where the parent could be deleted, potentially creating an orphaned child. This is not a security issue (the cross-space enforcement still works) and the race is rare enough that the current implementation is acceptable.

  • [INFO] The enforcement applies only at creation time via API/MCP. The security model assumes agents cannot directly modify database records (which they cannot via standard APIs). This is correct given the threat model.

Positive

  • Comprehensive security coverage: Both HTTP and MCP paths are protected with consistent validation logic.
  • Excellent test coverage: Six test scenarios covering cross-space rejection, same-space allowance, non-existent parents, no-parent backward compatibility, and both API surfaces.
  • Clear error messages: Responses explicitly mention "space enforcement" and name both spaces, making debugging straightforward.
  • Proper lock discipline: findAgentSpace() documents its lock precondition and both call sites correctly acquire s.mu.RLock().
  • Backward compatibility: No-parent spawns remain unaffected, preserving existing workflows.

Tmux Backend

Skipped — change does not touch this reviewer's scope.

Ambient Backend

Skipped — change does not touch this reviewer's scope.

Quality

Verdict: APPROVE — Excellent implementation with comprehensive test coverage and proper adherence to all quality standards.

Details

Findings

  • [INFO] handlers_agent.go:1543 — This change adds 21 lines to handlers_agent.go, which is already a grandfathered file at 1807 LOC (tracked as TASK-013). While not a blocker, consider extracting space validation logic to a dedicated helper if more space-related enforcement is added in the future.

  • [INFO] mcp_tools.go:1088 — Similarly, this adds 19 lines to mcp_tools.go, which is grandfathered at 1104 LOC. The enforcement logic is nearly identical to the HTTP handler version, suggesting potential for extraction to a shared validation function to reduce duplication.

  • [INFO] helpers.go:187 — The new findAgentSpace() helper properly documents the locking requirement ("Must be called with s.mu.RLock held"). This is good defensive documentation, though consider whether a runtime check or naming convention (e.g., findAgentSpaceLocked) would further prevent misuse.

Positive

  • server_test.go:4850-4981 — Outstanding test coverage. The 129-line test suite covers all critical paths: cross-space rejection (MCP + HTTP), same-space success (MCP + HTTP), non-existent parent rejection, and backward compatibility (no parent). This exemplifies the testing standards expected for security-sensitive changes.
  • Error messages — Both enforcement points (handlers_agent.go:1558-1562, mcp_tools.go:1103-1106) use clear, actionable error messages that explicitly name the conflicting spaces and the agent attempting the operation. This aids debugging and audit log analysis.
  • Security pattern — The implementation correctly enforces space boundaries at both API surfaces (HTTP endpoint and MCP tool), preventing privilege escalation via agent spawning. The enforcement is fail-secure: unknown parents are rejected rather than allowed.
  • Locking discipline — Proper use of s.mu.RLock() around findAgentSpace() calls, with explicit unlock before returning errors. No lock leaks or races detected.
  • Backward compatibility — The validation only triggers when parent/spawner is specified, preserving existing behavior for parentless agent creation. Test coverage confirms this (server_test.go:4968-4977).

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