Subscribe to get high-signal insights on how modern fintech is built.

engineering

Threat-Model a Fintech System, Not a Web App

OWASP catches injection and broken auth, but it won't catch the retry that donates twice from someone's bank account.

By Alex Kugell ·

You run the OWASP Top 10 against your fintech codebase. Broken access control, check. Injection, check. Cryptographic failures, check. You file the report, pass the SOC 2 audit, and move on.

Six months later, a timeout in your payment API causes a retry. The retry succeeds, and so did the original request. A customer's bank account gets debited twice, $2,500 instead of $1,250.

Your support team catches it on Monday morning.

OWASP didn't warn you about this. It wasn't designed to. The Top 10 was built for web applications, and the threat that just cost your customer real money has no web-application analogue.

Where OWASP stops

The OWASP Top 10 covers vulnerability classes that affect any web-facing application: injection, broken authentication, server-side request forgery, security misconfiguration. These are real risks in fintech systems too. A01, Broken Access Control, is probably the single most dangerous web vulnerability in a multi-tenant fintech because it can expose one customer's financial data to another.

But OWASP asks one question: can an attacker compromise the application?

A fintech threat model needs to ask a different question: can this system move money incorrectly? A system with perfect OWASP scores can still double-disburse, fabricate balances, or settle against stale sanctions data. The vulnerabilities that OWASP misses live in the money path, not the application layer.

OWASP Coverage vs. Fintech Threat Surface
ThreatOWASPFintechNote
Broken Access Control●●A01
Injection●●A03
Data Integrity Failures●●A08
Double Disbursement—●Retry-driven
Balance Fabrication—●Stale/forged data
Fee Manipulation—●Calc → settle gap
Sanctions Staleness—●OFAC screening lag
Webhook Forgery—●Trust boundary
Ledger Tampering—●Insider audit trail

The threats OWASP doesn't have a category for

Double disbursement. A payment API times out, the client retries, both requests succeed, and the customer loses money twice.

The system did exactly what it was designed to do. The design just didn't account for the fact that a timeout doesn't mean a failure.

The mitigation is idempotency keys at the ledger level, not the API level. An API-level deduplication that checks "did I see this request ID before" catches retries from the same client. A ledger-level deduplication that checks "did I already post this entry" catches retries from any source, including retries generated by internal queue processors, webhook handlers, and batch reconciliation systems.

Balance fabrication. Your system queries a third-party adapter, a bank API, a processor, a balance aggregator, and makes a disbursement decision based on the response. If that adapter is compromised or returns stale data, your system disburses against a balance that doesn't exist.

The trust boundary here is between your system and any external data source whose response triggers a financial decision.

Ledger tampering. OWASP's Software and Data Integrity Failures category covers the general class. But it frames the problem as "can an attacker modify data in transit or at rest."

In a fintech system, the specific risk is whether a malicious insider can modify the audit trail. A ledger entry that changes after posting doesn't just corrupt data. It makes the financial record unreliable for regulators, auditors, and dispute resolution. Append-only data structures and hash-chaining mitigate this, but only if the ledger is designed as immutable from the start.

Fee manipulation. A transaction is priced at 2.9% when the customer authorizes it. Between authorization and settlement, the fee changes to 3.5%. This can happen through configuration drift, a race condition in the pricing service, or deliberate manipulation by a compromised internal service. The gap between "fee calculated" and "fee charged" is a trust boundary that most threat models don't draw.

Sanctions screening staleness. You screen a recipient against the OFAC SDN list before disbursing. Your screening data was last updated 72 hours ago. In those 72 hours, the recipient was added to the list. You disbursed to a sanctioned entity using data that was accurate when you fetched it and wrong when you used it.

Webhook forgery. Your system receives a webhook from a processor confirming that a payment settled and credits the customer's balance. If that webhook was forged, the payment never actually settled, and you just created money from a POST request.

Webhook signature verification is the basic mitigation, but the deeper issue is that webhooks are trust boundaries that your system treats as ground truth.

How to apply STRIDE to money

STRIDE, Microsoft's threat classification framework, gives you six categories: Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, and Elevation of Privilege. The framework works for fintech systems, but only if you apply it to the right components.

Most teams run STRIDE against the application as a whole. For a fintech system, you need to run it against each component in the money path separately, because the threat profile changes at every trust boundary the money crosses.

The payment API has spoofing risks: can an attacker impersonate a legitimate client and initiate a transfer? The ledger carries tampering risks around whether entries can be modified after posting. And the settlement layer introduces repudiation risks, where the processor can deny it received your payment instruction, or you can deny you sent it.

Each component has different actors, different attack surfaces, and different mitigations. Draw your trust boundaries where money changes hands or where data crosses system ownership. Your API gateway, your processor integration, your bank connection, your webhook endpoints, and the boundary between your application and your ledger are all places where STRIDE should run independently.

What a fintech threat model actually looks like

A web application threat model starts with assets like user data, sessions, and credentials, then asks who can access them. A fintech threat model starts further downstream, at the money path itself, and asks what can go wrong at each step.

Map the money path. Trace every route money takes through your system, from the moment a customer initiates a transaction to the moment it settles in a bank account. Include the retry paths, the failure paths, and the reconciliation paths. The threat surface is the entire path, not just the happy path.

Identify the actors. Web threat models typically list external attackers, authenticated users, and administrators. A fintech threat model adds: compromised third-party integrations (processors, bank APIs, KYC providers), malicious insiders with ledger access, and your own system acting on stale or fabricated data.

Some of the most dangerous fintech threats come from components operating exactly as designed with inputs nobody anticipated.

Draw trust boundaries. Every point where data crosses ownership, from your system to a processor, from a processor to a bank, from a webhook to your ledger, is a trust boundary. Each boundary needs independent validation. A webhook from Stripe is trusted differently than a webhook from a white-label partner, and your system should enforce that difference.

Run STRIDE per component. Take each component in the money path and run all six STRIDE categories against it. Most will be empty. A few will surface risks you hadn't considered. The combination of ledger tampering and repudiation creates a scenario where a modified entry can't be attributed to anyone because the audit trail itself was altered.

Document residual risk. Every mitigation leaves a residual risk. Idempotency keys prevent duplicate disbursements but introduce a new risk: what happens when a legitimate retry is incorrectly deduplicated and a payment never settles? Document what you chose not to mitigate and why. This is the part SOC 2 auditors care about most, and bank partners will read it before they approve your integration.

Why the auditor won't catch it

SOC 2 requires a risk assessment under Trust Services Criteria CC3.2. It does not require a document called a threat model. Most fintech companies satisfy CC3.2 with an OWASP-based assessment, a penetration test report, and a vulnerability management policy. The auditor checks the box.

Your bank partner is the more demanding reviewer.

When a bank runs a security review before approving your integration, they ask questions that OWASP doesn't prepare you for. How do you prevent duplicate ACH debits? What happens if your balance check returns stale data? Can an internal engineer modify a ledger entry after it posts? How often is your sanctions screening data refreshed?

These questions target the money path. A threat model that only covers the application layer will leave you scrambling to answer them. The maker-checker pattern that banks use for high-value operations exists precisely because application-level controls are necessary but not sufficient.

Passing a bank security review on the first attempt means having already threat-modeled the money, not just the app.

Sources

Alex Kugell
Alex KugellAI/ML Engineer, Fintech Infrastructure

Writes Ledger Drift. Engineer building AI systems and financial infrastructure. Open source contributor to x402, ACK, and MPP.

Frequently Asked Questions

Why doesn't the OWASP Top 10 cover fintech-specific threats?
The OWASP Top 10 was built for web applications. It covers injection, broken access control, cryptographic failures, and similar vulnerability classes that apply to any web-facing software. Financial systems share those risks, but they also carry threats that have no web-application analogue: duplicate disbursements from retries, ledger tampering that changes the audit trail, fee manipulation between calculation and settlement, and stale sanctions screening data. These threats target the money path, not the application layer, and a threat model built only from OWASP categories will miss them entirely.
What is double disbursement and why is it a fintech-specific risk?
Double disbursement occurs when a payment system retries a failed or timed-out request and the original request actually succeeded. The result is two payments instead of one. This is the most common money-path failure in payment systems because retries are a standard reliability pattern in distributed systems. Without idempotency keys that deduplicate requests at the ledger level, every timeout creates a window for duplicate money movement. OWASP does not cover this because it is not a vulnerability in the traditional sense. The system is working as designed. The design just happens to move money twice.
How do you apply STRIDE to a fintech system?
STRIDE categorizes threats into six types: Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, and Elevation of Privilege. For a fintech system, you apply STRIDE to each component along the money path rather than the application as a whole. A payment API has spoofing risks at the authentication layer. The ledger has tampering risks if entries can be modified after posting. Settlement has repudiation risks if a processor can deny receiving a payment instruction. Each component gets its own STRIDE analysis because the threat profile changes at every trust boundary the money crosses.
What threats should a fintech threat model cover that a web app threat model doesn't?
At minimum: double disbursement from retries, balance fabrication from compromised integrations returning inflated values, ledger tampering including both external attacks and insider modification of the audit trail, fee manipulation between the calculation and settlement of a transaction, sanctions screening staleness where disbursements reach blocked entities because screening data is hours or days old, and webhook forgery where an attacker sends fake settlement confirmations. Each of these targets the money path specifically. A web application threat model focuses on the application layer and will not surface them.
Does SOC 2 require a formal threat model?
SOC 2 does not require a document labeled threat model. It requires a risk assessment under Trust Services Criteria CC3.2, which asks organizations to identify threats, assess their likelihood and impact, and document mitigations. A threat model is one way to satisfy that requirement and is the most structured approach. Auditors typically look for documentation of the scope, a prioritized threat register, mitigation status, and evidence that the assessment is updated after significant system changes. A fintech that passes its threat model to the auditor with only OWASP categories will satisfy the checkbox, but it will miss the financial risks that a bank partner's security review will catch.

Built by Trio, a fintech-native engineering partner helping teams build the next generation of financial technology and infrastructure.

Subscribe to Ledger Drift for high-signal insights into how modern fintech is built, from systems to code to teams.

Keep reading

engineeringReconciliation Is Where the Money HidesEvery fintech has a ledger and a bank account, and the numbers between them disagree more often than anyone admits.
fintechFraud Detection 101Your fraud model has 45 milliseconds, 99.99% legitimate transactions, and a customer who will leave if you get it wrong.
analysisPayPal Wants Developers to Build on PYUSDPYUSDx lets developers issue custom stablecoins backed by PayPal's dollar, and the real play is making PYUSD the reserve layer.
View more ›