T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/mai_registry.py:228- Finding
Merchant Snapshot Push Permits Cross-Tenant Order and Marketplace Data Tampering
- Content
View full analysis
Vulnerability Details
File Location:
scripts/mai_registry.py:228-235, 569-582
Vulnerability Type: Incomplete object-level authorization in snapshot ingestion
Risk Level: HighVulnerable Code
The snapshot merge function accepts and persists orders, messages, reviews, and inventory events without validating their ownership:
python for order_id, order in snapshot.get("orders", {}).items(): registry["orders"][order_id] = order counts["orders"] += 1 counts["messages"] = dedupe_list_append(registry["messages"], snapshot.get("messages", [])) counts["reviews"] = dedupe_list_append(registry["reviews"], snapshot.get("reviews", [])) counts["inventory_events"] = dedupe_list_append( registry["inventory_events"], snapshot.get("inventory_events", []), )The
/sync/pushauthorization logic validates only the merchant and product portions of the payload before passing the complete payload tomerge_snapshot():python if parsed.path == "/sync/push": principal = self.require_authenticated(principal) if principal["role"] == "merchant": allowed = principal.get("merchant_id", "") merchants = set(payload.get("merchants", {}).keys()) product_merchants = { product.get("merchant_id", "") for product in payload.get("products", {}).values() } if merchants - {allowed} or product_merchants - {allowed}: raise PermissionError(f"merchant access required: {allowed}") elif principal["role"] != "admin": raise PermissionError("merchant or admin role required") counts = merge_snapshot(registry, payload)Technical Analysis
The registry applies tenant authorization to
merchantsandproducts, but not to the other collections accepted by the same endpoint. Consequently, any authenticated merchant can provide empty or correctly scoped merchant and product maps while addi ...[truncated 1944 chars]- Remediation
View remediation
Remediation Suggestions
- Make merchant snapshot pushes catalog-only at the server boundary. Reject merchant payloads containing non-empty
orders,messages,inventory_events, synchronization events, or other privileged collections. - Do not pass the original unrestricted payload to
merge_snapshot(). Construct an allowlisted payload containing only validated merchant and product records. - If review publication is allowed, validate that each review is associated with an authorized and verified transaction rather than accepting arbitrary snapshots.
- Restrict full-state migration to administrators through a separate endpoint and require explicit migration authorization.
- Validate the
merchant_idof every nested record, including orders, messages, reviews, and inventory events. - Prevent snapshot ingestion from overwriting existing orders. Use dedicated, state-transition-aware order endpoints with optimistic concurrency or immutable event records.
- Add negative tests proving that a merchant cannot create or overwrite objects associated with another merchant or buyer.
- Record an audit event for every administrative migration or attempted cross-tenant write.
- Make merchant snapshot pushes catalog-only at the server boundary. Reject merchant payloads containing non-empty
