Summary
ComplianceGuard.verify_aml_flag — the AML control — has two failure modes on adversarial numeric input, both CONFIRMED BY EXECUTION:
- Crash instead of verdict: NaN or Infinity amounts raise an unhandled
z3types.Z3Exception: parser error out of the guard. The exception propagates through UCPIntegration.verify_payment_token with no try/except — so a sanctioned-country, KYC-less payment with a NaN amount raises instead of returning BLOCKED/PENDING_REVIEW. Whether the transaction then proceeds is decided by whatever upstream except the integrator happens to have. An AML control must return a conservative verdict, never raise.
- Negative amounts never flag:
verify_aml_flag(amount=-1_000_000, country_code="US", llm_flagged=False) → compliant=True. amount >= threshold passes for any negative value; sign is never validated.
Location
qwed_finance/compliance_guard.py:96-101 → :123 — s.add(amt == amount) with a non-finite float crashes Z3's RealVal
qwed_finance/compliance_guard.py:96 — should_flag = amount >= threshold or is_high_risk (no sign check)
qwed_finance/integrations/ucp.py:134-143 — calls the guard unguarded; exception escapes verify_payment_token
Evidence (CONFIRMED BY EXECUTION, v2.1.0 @ 26d6dd0)
verify_aml_flag(amount=float("nan"), country_code="KP", llm_flagged=False)
→ z3types.Z3Exception (unhandled)
UCPIntegration().verify_payment_token({"amount": float("nan"),
"customer_country":"KP","kyc_verified":False}) → same exception
verify_aml_flag(amount=-1_000_000, country_code="US", ...) → compliant=True
Impact
The failure mode of an AML/sanctions gate on hostile input is delegated to caller error-handling. A swallowed exception upstream = unflagged transaction. The negative-amount gap additionally lets any negative-amount path bypass flagging outright.
Fix
- Finite-check at entry: non-finite amount → BLOCKED/compliant=False verdict (never reach the solver).
- Wrap the Z3 section with a fail-closed fallback (the non-Z3
_verify_aml_fallback already exists — route to it on solver failure).
- Decide negative-amount policy explicitly: flag on
abs(amount) >= threshold, or reject negatives as invalid input.
- Same finite-guard for
UCPIntegration.verify_payment_token before the amount checks (NaN currently also slips past amount > max / amount <= 0 comparisons since both are False for NaN).
Summary
ComplianceGuard.verify_aml_flag— the AML control — has two failure modes on adversarial numeric input, both CONFIRMED BY EXECUTION:z3types.Z3Exception: parser errorout of the guard. The exception propagates throughUCPIntegration.verify_payment_tokenwith no try/except — so a sanctioned-country, KYC-less payment with a NaN amount raises instead of returning BLOCKED/PENDING_REVIEW. Whether the transaction then proceeds is decided by whatever upstreamexceptthe integrator happens to have. An AML control must return a conservative verdict, never raise.verify_aml_flag(amount=-1_000_000, country_code="US", llm_flagged=False)→compliant=True.amount >= thresholdpasses for any negative value; sign is never validated.Location
qwed_finance/compliance_guard.py:96-101 → :123—s.add(amt == amount)with a non-finite float crashes Z3'sRealValqwed_finance/compliance_guard.py:96—should_flag = amount >= threshold or is_high_risk(no sign check)qwed_finance/integrations/ucp.py:134-143— calls the guard unguarded; exception escapesverify_payment_tokenEvidence (CONFIRMED BY EXECUTION, v2.1.0 @ 26d6dd0)
Impact
The failure mode of an AML/sanctions gate on hostile input is delegated to caller error-handling. A swallowed exception upstream = unflagged transaction. The negative-amount gap additionally lets any negative-amount path bypass flagging outright.
Fix
_verify_aml_fallbackalready exists — route to it on solver failure).abs(amount) >= threshold, or reject negatives as invalid input.UCPIntegration.verify_payment_tokenbefore the amount checks (NaN currently also slips pastamount > max/amount <= 0comparisons since both are False for NaN).