-
-
A serverless AWS design that uses Step Functions, DynamoDB and Amazon SES to hold, verify and decide each change.
-
An email can request a bank-detail change but cannot authorize one, because verification goes only to the trusted registry.
-
A genuine change is confirmed through the registered contact, passes the secondary checks, and only then is it applied.
-
A suspicious supplier change is held, the AI explains why, and the account on file stays unchanged.
Inspiration
Invoice-redirection fraud works because the fake email carries its own proof: a new bank account and a friendly "please confirm on this number". An accounts-payable clerk who calls that number has just verified the fraudster with the fraudster. We wanted a system where an email can request a payment change but can never authorize one.
What it does
PayeeChange Guardian sits between a supplier's "we changed banks" email and the payment record.
- It holds the change immediately. The account on file stays in force.
- It scores the request with deterministic signals: changed account, new contact details, unseen sender domain, failed SPF/DKIM, pressure wording, unusual amount.
- It verifies only through the contact already in the trusted vendor registry. Any phone number or address inside the email is ignored and shown as "never used".
- The registered contact gets one-time Yes / No links. A "No" blocks the change. A "Yes" still has to pass extra checks (IBAN checksum, account not registered to another vendor) before the record is updated. Anything unclear goes to a human approver.
- Every step is on an audit timeline, and the dashboard shows the account before and after, so you can see whether protected data actually changed.
- An AI analyst adds a plain-English note ("lookalike domain, urgency, redirected contact") to help the clerk. It is advisory only.
How we built it
Everything is deployed with AWS SAM in us-east-1: API Gateway and Lambda (intake, policy, dashboard), Step Functions with waitForTaskToken to hold the change until the supplier answers, DynamoDB (trusted registry and cases), EventBridge and SNS (alerts for blocked, escalated and stuck cases), SSM Parameter Store (API key), and Amazon SES v2 (sesv2.send_email) for verification and approver mail. Confirm pages use GET to preview and POST to decide, with random one-time tokens, so email scanners that prefetch links cannot answer for the supplier.
The AI is deliberately boxed in. A separate background Lambda asks an external LLM (Gemini free tier today; Amazon Bedrock is a one-line setting) for a short note, and a classifier turns free-text replies into a label only. The model never chooses a destination, never approves, and a DENY always blocks. If the model is slow or down, the case still works and the page says so.
WhatsApp (End User Messaging Social) and SMS (End User Messaging SMS) are implemented in the same channel layer and unit-tested against the SDK call shapes. They are not enabled in the deployed account because the service access was not available to us.
Challenges we ran into
- Service access: our AWS free plan blocked Bedrock, WhatsApp and SMS. We rebuilt the live path around SES and kept the other channels behind a setting.
- Email security scanners: link prefetching can "click" a confirmation. We moved the decision behind a POST and burn tokens on first use.
- Keeping the model out of the blast radius: prompt injection in the email must not change where verification goes, so the destination is never an input to the model. We test this.
- Free-tier LLM latency: notes were timing out, so the AI moved to an asynchronous worker with model fallback. The decision path never waits on it.
Accomplishments that we're proud of
- The attack case ends blocked with the registered account untouched, and the legitimate case ends approved, both visible end to end in a live deployment.
- 38 automated tests, including token reuse, masked public views, conditional replies never approving, and model failure never breaking a case.
- A dashboard that explains the decision instead of just showing a score.
What we learned
Put the model where it can explain, not where it can be fooled. The strongest control here is not smarter AI. It is refusing to trust the channel the request arrived on.
What's next for PayeeChange Guardian
Enable WhatsApp and SMS fallbacks, add Amazon Bedrock AgentCore for multi-step case handling, connect to a real ERP or payment system, and put the dashboard behind SSO with maker-checker approvals.
Built With
- amazon-api-gateway
- amazon-dynamodb
- amazon-eventbridge
- amazon-ses
- amazon-sns
- amazon-web-services
- aws-budgets
- aws-cloudformation
- aws-lambda
- aws-sam
- aws-step-functions
- aws-systems-manager
- google-gemini
- javascript
- python
Log in or sign up for Devpost to join the conversation.