What Happens When Your AI Submits a Purchase Order to a Blocked Vendor?
What Happens When Your AI Submits a Purchase Order to a Blocked Vendor?
Category: Procurement & Supply Chain | Reading time: 5 min
A Scenario That Will Happen
Your procurement AI receives an invoice from a vendor that was added to your blocked list two weeks ago — a supplier whose parent company was sanctioned by OFAC following geopolitical events. The procurement team updated the vendor status in the master file. But the invoice email arrived before the status propagated, was processed by the AI, and is now queued for payment.
What happens next depends entirely on your system's architecture.
In a system without policy enforcement: the payment is queued, the AP clerk batch-approves it as routine, and the wire goes out. The error is discovered weeks later during a compliance review.
In a system with Taos governance: the policy engine catches vendor_status = "blocked" before a single database record is created, raises a hard deny, cleans up the queue entry, and notifies the procurement team — all in under 100 milliseconds.
Technically, TAOS enforces that a vendor blocked check runs at the governed payment step and blocks the agent’s attempt to pay whenever policy says the vendor should be blocked. That sequencing and stop decision live in the kernel, not in model discretion or an optional guardrail prompt.
Let's walk through the second scenario in detail.
The Sequence of Events
T+0ms — Invoice arrives The AI receives the invoice PDF via email integration. It extracts supplier name, invoice number, line items, and total: $12,400.
T+50ms — Vendor lookup The kernel queries the vendor master for the extracted supplier name. Returns:
{
"vendor_id": "V-8821",
"vendor_name": "Meridian Industrial Supplies",
"vendor_status": "blocked",
"block_reason": "OFAC-SDN-2024-0312",
"is_ofac_cleared": false
}
T+55ms — Policy evaluation
The Rego engine evaluates, and the kernel looks up denial_mode for this step definition ("hard"):
deny_blocked_vendor {
input.vendor_status == "blocked"
}
deny_blocked_vendor {
input.is_ofac_cleared == false
}
action = "deny" { deny_blocked_vendor }
rule_fired = "deny_blocked_vendor" { deny_blocked_vendor }
Result: action = "deny", rule_fired = "deny_blocked_vendor".
T+56ms — PolicyDeniedError raised (hard mode)
The kernel sends PolicyDenied with denial_mode = "hard". The client plugin raises PolicyDeniedError immediately — the LLM never receives or reformulates the denial. The payment creation step is never called and the agent run terminates.
This is the crucial distinction from denial_mode = "soft", where the denial dict is returned to the LLM as the tool result and the agent continues. For OFAC blocks, soft mode is unacceptable — it allows the LLM to dilute or rephrase the regulatory reason and the agent might attempt an alternative path.
T+57ms — Saga compensation runs
Steps completed before the policy check (invoice extraction, vendor lookup) are compensated: invoice status reset to pending_review.
T+58ms — Audit event written Immutable record created:
{
"event_type": "POLICY_DENIED",
"rule_fired": "deny_blocked_vendor",
"invoice_id": "INV-2024-0881",
"vendor_id": "V-8821",
"vendor_status": "blocked",
"block_reason": "OFAC-SDN-2024-0312",
"amount": 12400.00,
"submitted_by": "ai_agent",
"initiated_by": "ap_team_import",
"timestamp": "2024-03-15T09:23:00.058Z"
}
T+100ms — Alert dispatched Operations notified: "Invoice INV-2024-0881 from Meridian Industrial Supplies blocked — vendor OFAC-sanctioned (SDN-2024-0312). Invoice held in pending_review queue."
No payment record created. No ERP entry. No bank transaction. The system is clean.
Why the Hard Deny Has No Override
The deny_blocked_vendor rule in the Taos payment policy is intentionally structured without an override path. Unlike tier-based approval routing — where a higher authority can approve an otherwise-blocked transaction — OFAC sanctions are absolute. There is no business justification that permits payment to a sanctioned entity.
This is enforced in the policy by the rule structure: the rule fires before any allow condition is evaluated, and no override_approved input can change the outcome:
# This rule fires FIRST and cannot be overridden
# No input combination produces allow=true for a blocked vendor
default allow = false
allow {
not deny_blocked_vendor
# ... other conditions
}
# deny_blocked_vendor is terminal — no override path
deny_blocked_vendor {
input.vendor_status == "blocked"
}
When a compliance auditor asks "could anyone have approved a payment to this vendor through your AI system?" — the answer is no, and the policy code proves it.
The Compliance Team's View
The compliance team monitoring blocked vendor incidents sees, in their dashboard:
- Invoice source — which channel delivered the invoice (email import, API, manual upload)
- Vendor block reason — OFAC SDN, internal fraud flag, contractual exclusion, etc.
- Block detection latency — time from invoice receipt to policy deny
- Volume trend — how many blocked vendor invoices per week, from which sources
If a particular channel is consistently delivering invoices from blocked vendors, it suggests either a data quality problem (vendor master not synced) or a potential supply chain infiltration attempt.
Handling the Business Impact
The blocked payment still represents a business need — presumably the organisation needed whatever Meridian Industrial Supplies was providing. The operations team's response process:
- Review the block reason — OFAC, fraud flag, contractual exclusion?
- For OFAC: immediately cease all business with the vendor, refer to legal
- For fraud flag: investigate, escalate to procurement security
- For contractual exclusion: route to procurement for alternative supplier
- Update the invoice status and source the goods/services elsewhere
The AI handles the detection and containment. Humans handle the remediation. The roles are clear.
Testing Your Block Detection
One advantage of policy-as-code governance is that you can test it explicitly. Add this to your CI/CD pipeline:
async def test_blocked_vendor_is_denied():
result = await run_governed_payment(
invoice_id="TEST-INV-BLOCKED",
mock_vendor_status="blocked",
mock_is_ofac_cleared=False,
)
assert result["policy_denied"] == True
assert result["error"] is not None
assert "deny_blocked_vendor" in result["policy_log"][0]["decision"]["rule_fired"]
assert result.get("payment_id") is None # No payment created
This test runs on every code change. If someone accidentally modifies the policy in a way that allows blocked vendor payments, the test fails before the code ships.
The Bottom Line
Blocked vendor encounters are not edge cases — they're inevitable in any procurement operation of scale. The question is whether your system catches them at millisecond speed with a clean rollback, or whether they surface weeks later in a compliance review.
Policy enforcement at the kernel layer guarantees the first outcome. Every time. With a complete audit trail.
Tags: OFAC compliance, blocked vendor, procurement AI, AI governance, supply chain compliance, sanctions enforcement