Task Summary
Agents in the agent service are not isolated per user, and the REST/WebSocket routes have no authorization. Anyone who can reach the service and supply an agent id can read or drive any agent.
Specific gaps (agent-service/src/server.ts, agent-service/src/api/auth-api.ts):
| Gap |
Detail |
| No ownership check |
Every /agents/:id* route and WS /agents/:id/react resolves an agent purely by id — no check that the caller owns it. |
| Enumerable ids |
ids are sequential: agent-${++agentCounter}. Trivially guessable. |
| Global listing |
GET /agents returns all agents across all users. |
| Token not bound |
userToken is only used at creation time to load the delegate workflow; later requests need no token and the agent is never bound to an owner. |
| Signature not verified |
validateToken only checks exp; extractUserFromToken base64-decodes the JWT payload without verifying the signature, so a forged/edited token is accepted. |
Before: caller + any agent id -> full read/control of that agent
After: caller + token (verified) -> only that user's own agents
Proposed work: verify JWT signatures (not just expiry); bind each agent to an owner at creation; authorize every /:id route and the websocket against the caller's identity; scope GET /agents to the caller; and use non-guessable agent ids.
Task Type
Task Summary
Agents in the agent service are not isolated per user, and the REST/WebSocket routes have no authorization. Anyone who can reach the service and supply an agent id can read or drive any agent.
Specific gaps (
agent-service/src/server.ts,agent-service/src/api/auth-api.ts):/agents/:id*route andWS /agents/:id/reactresolves an agent purely by id — no check that the caller owns it.agent-${++agentCounter}. Trivially guessable.GET /agentsreturns all agents across all users.userTokenis only used at creation time to load the delegate workflow; later requests need no token and the agent is never bound to an owner.validateTokenonly checksexp;extractUserFromTokenbase64-decodes the JWT payload without verifying the signature, so a forged/edited token is accepted.Proposed work: verify JWT signatures (not just expiry); bind each agent to an owner at creation; authorize every
/:idroute and the websocket against the caller's identity; scopeGET /agentsto the caller; and use non-guessable agent ids.Task Type