T05 · Unauthorized Access and Privilege Escalation
- Location
python/scripts/server.py:575- Finding
Unauthenticated Inbox Disclosure and Message Delivery Interference
- Content
View full analysis
', methods=['GET']) def receive_messages(vault_id: str): """ Receive unread messages for a vault. """ limit = request.args.get('limit', 50, type=int) limit = min(limit, 100) debug = request.args.get('debug', 'false').lower() == 'true' db = get_db() now = datetime.now(timezone.utc).isoformat() rows = db.execute(''' SELECT id, sender_vault_id, message_json, signature, encrypted_payload_json, created_at FROM messages WHERE recipient_vault_id = ? AND delivered_at IS NULL AND expires_at > ? ORDER BY created_at ASC LIMIT ? ''', (vault_id, now, limit)).fetchall() messages = [] message_ids = [] for row in rows: msg_data = { 'message_id': row['id'], 'sender': row['sender_vault_id'], 'message': json.loads(row['message_json']), 'signature': row['signature'], 'received_at': now, } if row['encrypted_payload_json']: msg_data['encrypted_payload'] = json.loads( row['encrypted_payload_json'] ) messages.append(msg_data) message_ids.append(row['id']) # Mark as delivered if message_ids: placeholders = ','.join(['?' for _ in message_ids]) db.execute(f''' UPDATE messages SET delivered_at = ? WHERE id IN ({placeholders}) ''', [now] + message_ids) db.commit() return json_response({ 'messages': messages, 'count': len(messages), }) ``` ### Technical Analysis The inbox route does not use the server's `@requires_auth` decorator and performs no check that the caller controls the va ...[truncated 2029 chars]- Remediation
View remediation
`. 2. Verify that the authenticated identity matches the requested mailbox: ```python @app.route('/receive/', methods=['POST']) @requires_auth def receive_messages(vault_id): if g.vault_id != vault_id: return error_response( 'Not authorized to access this mailbox', 403, 'forbidden' ) ``` 3. Prefer deriving the mailbox exclusively from `g.vault_id` rather than accepting a public vault ID in the route. 4. Do not mark messages delivered merely because they were fetched. Use an authenticated, recipient-authorized acknowledgment operation after successful local processing. 5. If fetch-time delivery marking remains necessary, perform the selection and update atomically and bind both operations to the authenticated recipient. 6. Remove or strictly protect the `debug` response because it exposes additional mailbox metadata. 7. Add tests proving that unsigned requests and requests signed by another vault receive `401` or `403` and do not alter `delivered_at`. 8. Consider making end-to-end encryption the default, while recognizing that encryption does not replace mailbox authorization. ]]>
