T05 · Unauthorized Access and Privilege Escalation
- Location
src/CommunicationHub.ts:51- Finding
Cross-Agent Message Disclosure and Unauthorized Acknowledgement
- Content
View full analysis
Vulnerability Details
File Location:
src/CommunicationHub.ts:51-114
Vulnerability Type: Missing object-level and function-level authorization
Risk Level: HighVulnerable 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
View remediation
Remediation Suggestions
- Introduce an authenticated caller context for every public operation:
ts interface CallerContext { agentId: string; roles: string[]; } - Derive the requesting agent from a validated session or unforgeable capability rather than accepting it solely as an input parameter.
- Restrict message reads to records where the authenticated caller is the sender or recipient.
- Permit global message history only through a separately protected administrator or auditor API.
- Before acknowledgement, retrieve the message and verify that its
recipientIdequals the authenticated caller's agent ID. - Restrict queue inspection and draining to the authenticated recipient.
- Apply state-transition checks so only delivered messages can be acknowledged and only pending messages can be delivered.
- Add negative authorization tests covering cross-agent reads, queue draining, and acknowledgement attempts.
- Introduce an authenticated caller context for every public operation:
