Summary
The tag-policy permission middleware falls back to reading caller identity from client-controlled HTTP headers when DID resolution fails, allowing any caller to spoof another agent's tags and bypass policy enforcement.
Context
In permission.go:151, when GetVerifiedCallerDID cannot produce a callerAgentID, the middleware falls back to reading X-Caller-Agent-ID and then X-Agent-Node-ID from request headers. These headers are set by the client, not the control plane. An attacker can set these headers to impersonate a high-privilege agent, inherit its tags, and pass tag-based policy checks for resources they should not access. The fallback was likely added for backward compatibility but creates a complete authorization bypass for all tag-policy-protected routes.
Scope
In Scope
- Remove the header-based caller identity fallback from the tag-policy permission middleware.
- When DID resolution fails or produces no caller ID, treat the caller as anonymous/untagged (never trust client-supplied identity headers for authorization decisions).
- Log a warning when DID resolution fails so operators can detect misconfigured agents.
Out of Scope
- Changing the DID resolution logic itself.
- Removing the headers from the wire entirely — they may still be used for non-authorization purposes (e.g. logging/tracing), just not for security decisions.
- Refactoring the permission middleware beyond the identity-source fix.
Files
control-plane/internal/server/middleware/permission.go:151 — remove fallback to X-Caller-Agent-ID / X-Agent-Node-ID for authorization decisions
control-plane/internal/server/middleware/permission_test.go — add test: request with spoofed X-Caller-Agent-ID header is NOT granted the spoofed agent's tags
Acceptance Criteria
Notes for Contributors
Severity: HIGH
Before removing the fallback, check whether any integration tests or the agent SDK relies on these headers for the happy path. If so, fix those callers to use DID auth instead, rather than keeping the insecure fallback. The GetVerifiedCallerDID helper should be the single source of truth for caller identity in this middleware.
Summary
The tag-policy permission middleware falls back to reading caller identity from client-controlled HTTP headers when DID resolution fails, allowing any caller to spoof another agent's tags and bypass policy enforcement.
Context
In
permission.go:151, whenGetVerifiedCallerDIDcannot produce acallerAgentID, the middleware falls back to readingX-Caller-Agent-IDand thenX-Agent-Node-IDfrom request headers. These headers are set by the client, not the control plane. An attacker can set these headers to impersonate a high-privilege agent, inherit its tags, and pass tag-based policy checks for resources they should not access. The fallback was likely added for backward compatibility but creates a complete authorization bypass for all tag-policy-protected routes.Scope
In Scope
Out of Scope
Files
control-plane/internal/server/middleware/permission.go:151— remove fallback toX-Caller-Agent-ID/X-Agent-Node-IDfor authorization decisionscontrol-plane/internal/server/middleware/permission_test.go— add test: request with spoofedX-Caller-Agent-IDheader is NOT granted the spoofed agent's tagsAcceptance Criteria
X-Caller-Agent-IDheader for a high-privilege agent but no valid DID is treated as anonymous/untagged, not as that agentgo test ./control-plane/...)make lint)Notes for Contributors
Severity: HIGH
Before removing the fallback, check whether any integration tests or the agent SDK relies on these headers for the happy path. If so, fix those callers to use DID auth instead, rather than keeping the insecure fallback. The
GetVerifiedCallerDIDhelper should be the single source of truth for caller identity in this middleware.