other
Warning
- Location
- scripts/ari.py:1103
- Finding
- Server-Controlled Auto-Confirmation Can Trigger Paid Analysis Without Explicit Per-Operation Consent## Vulnerability Details **File Location**: `scripts/ari.py:1103-1112` **Vulnerability Type**: Server-controlled authorization of a paid operation **Risk Level**: Medium **Category**: `other: Unconfirmed paid operation` ### Vulnerable Code ```python q_payload = quote_payload(kind, asin, site, competitor, competitor_site) quote = request_json("POST", "/api/v1/analysis/quote", q_payload) if not ok(quote): return quote q_data = data_of(quote) or {} # First-use confirmation exemption: generate the report immediately when # the server permits automatic confirmation. auto_confirmed = False if not confirm and q_data.get("autoConfirm") and q_data.get("sufficient"): confirm = True auto_confirmed = True if not confirm: return {"success": True, "data": {"confirmationRequired": True, "quote": q_data, "webUrl": q_data.get("webUrl"), "message": "The report will only be generated and credits deducted after the user confirms with --confirm."}, "links": links()} ``` The same trust model is also applied to the combined collection and VOC workflow at `scripts/ari.py:1308-1320`: ```python auto_max = int(analysis_quote.get("autoConfirmMaxCredits") or 0) auto_confirmed = (not args.confirm and bool(analysis_quote.get("autoConfirm")) and sufficient and total_credits <= auto_max) if not args.confirm and not auto_confirmed: combined_quote["autoConfirmRemaining"] = analysis_quote.get("autoConfirmRemaining") emit({"success": True, "data": combined_quote, "links": links()}, args.compact) return if not sufficient: emit(error_obj( "ARI_INSUFFICIENT_CREDITS", 402, "Insufficient credits", "Collection and VOC require %d credits; current balance is %d." % (total_credits, total_balance)), args.compact) return ``` ### Technical Analysis T ...[truncated 3436 chars]
- Remediation
- ## Remediation Suggestions 1. **Require explicit local confirmation by default.** Never change `confirm` from false to true solely because an API response contains `autoConfirm`. ```python if not confirm: return { "success": True, "data": { "confirmationRequired": True, "quote": q_data, }, "links": links(), } ``` 2. **Separate quoting from execution.** Ensure quote commands cannot invoke collection or analysis under any server response. Provide a dedicated preview-only mode whose execution path contains no calls to chargeable endpoints. 3. **Require a prior user-controlled opt-in for automatic spending.** If automatic confirmation is retained, activate it only after the user explicitly configures a maximum credit threshold. Store or retrieve that preference separately from the current quote response and display the active threshold before execution. 4. **Bind authorization to the quoted request.** Use a request identifier, quoted cost, operation type, ASIN, site, and expiration time. Reject execution if any field differs from the operation explicitly approved by the user. 5. **Apply a hard local ceiling.** Enforce a conservative local maximum in addition to the server policy, and require fresh confirmation whenever the price changes or a collection step is added. 6. **Add audit logging.** Record whether authorization came from an explicit `--confirm` option or a previously configured user threshold, together with the request ID and charged amount. Do not log the API key. 7. **Add regression tests.** Verify that `autoConfirm: true` cannot trigger a paid request when no explicit confirmation or preconfigured user spending authorization exists.
