T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- src/CommunicationHub.ts:51
- Finding
- Cross-Agent Message Disclosure and Unauthorized Acknowledgement## Vulnerability Details **File Location**: `src/CommunicationHub.ts:51-114` **Vulnerability Type**: Missing object-level and function-level authorization **Risk Level**: High ### Vulnerable Code ```ts public acknowledgeMessage(messageId: string): MessageRecord { const record = this.getMessage(messageId); const acknowledgedAt = nowIso(); this.db .prepare( `UPDATE messages SET status = 'acknowledged', acknowledged_at = ? WHERE id = ?`, ) .run(acknowledgedAt, messageId); return this.getMessage(messageId); } public drainOfflineQueue(agentId: string): MessageRecord[] { this.sessions.getAgent(agentId); if (!this.sessions.isAgentOnline(agentId)) { return []; } const deliveredAt = nowIso(); this.db .prepare( `UPDATE messages SET status = 'delivered', delivered_at = ? WHERE recipient_id = ? AND status = 'pending'`, ) .run(deliveredAt, agentId); return this.listMessages({ recipientId: agentId, status: "delivered" }); } public getPendingMessages(agentId: string): MessageRecord[] { return this.listMessages({ recipientId: agentId, status: "pending" }); } public listMessages(query: MessageQuery = {}): MessageRecord[] { const conditions: string[] = []; const values: Array<string | number> = []; if (query.senderId) { conditions.push("sender_id = ?"); values.push(query.senderId); } if (query.recipientId) { conditions.push("recipient_id = ?"); values.push(query.recipientId); } if (query.status) { conditions.push("status = ?"); values.push(query.status); } if (query.kind) { conditions.push("kind = ?"); values.push(query.kind); } const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : ""; const limit = query.limit ?? 100; const rows = this.db .prepare(`SELECT * FROM messages ${w ...[truncated 2414 chars]
- Remediation
- ## Remediation Suggestions 1. Introduce an authenticated caller context for every public operation: ```ts interface CallerContext { agentId: string; roles: string[]; } ``` 2. Derive the requesting agent from a validated session or unforgeable capability rather than accepting it solely as an input parameter. 3. Restrict message reads to records where the authenticated caller is the sender or recipient. 4. Permit global message history only through a separately protected administrator or auditor API. 5. Before acknowledgement, retrieve the message and verify that its `recipientId` equals the authenticated caller's agent ID. 6. Restrict queue inspection and draining to the authenticated recipient. 7. Apply state-transition checks so only delivered messages can be acknowledged and only pending messages can be delivered. 8. Add negative authorization tests covering cross-agent reads, queue draining, and acknowledgement attempts.
