What Nigerian banks mean when they say 'glitch'
When a Nigerian commercial bank wakes up to news of customers withdrawing billions of Naira due to an unexpected balance increase, the public relations department issues a standard statement blaming a "technical glitch." We saw this during recent system migrations at Access Bank and GTBank, where users woke up to massive, unexpected credits in their accounts. We saw it when Union Bank and Sterling Bank experienced transfer timeouts that debited the sender but credited the receiver.
None of these institutions published a technical root cause analysis. Yet, the mechanics behind these events are entirely explainable. They are not database corruption or random bit flips. Instead, they are the direct result of unhandled edge cases in distributed transaction rollbacks across domestic payment switches.
The architectural shift that caused this
To understand why these failures occur, you have to look at the architectural evolution of Nigerian commercial banking over the past decade. Historically, traditional banks operated on monolithic core banking systems like Finacle and T24.
These monoliths ran on a single database backend. Transactions were synchronous and bound by strict ACID properties. If a customer initiated a bank-to-bank transfer, the system locked the rows, verified the balance, debited the sender, and committed the changes. If any step failed, the database rolled back the entire operation to its initial state.
Today, banks have migrated to microservices-based or layered architectures to handle the massive transaction volume driven by mobile banking. The core banking engine, the mobile API gateway, the ledger microservice, and the integration layer for the Nigeria Inter-Bank Settlement System (NIBSS) are now separate, independent services. These services run on different databases and communicate asynchronously. In this environment, you lose immediate ACID guarantees. You are forced to operate in a state of eventual consistency, which introduces entirely new failure modes.
What a Saga pattern is and how it fails
Because you cannot run a two-phase database commit across external networks like NIBSS, MTN, Airtel, or digital wallet provider APIs, engineers use the Saga pattern. A Saga is a design pattern that manages distributed transactions through a sequence of local transactions. Each step updates its local database.
In a distributed banking architecture, a simple money transfer involves several distinct local transactions:
- Step A: Debit the source account microservice.
- Step B: Credit the destination account microservice.
- Step C: Update the main ledger microservice.
- Step D: Trigger the notification microservice.
If one of these steps fails, the orchestrator must execute compensating transactions (rollbacks) in reverse order to return the system to a consistent state. For instance, if Step C (ledger update) fails, the orchestrator must fire a compensating transaction to refund the debit executed in Step A.
The architecture breaks when a compensating transaction itself fails. If Step B (destination credit) succeeds but Step C (ledger update) fails, the orchestrator triggers a compensating rollback to reverse the credit at the destination. If this reversal fails due to a network partition or a crash in the destination service, the execution stops. The money is credited to the receiver, but your ledger has no record of the matching debit.
The double-credit specific pattern
The double-credit is the most common failure pattern observed during high-volume periods. Let us trace how this happens at the API level.
A transfer orchestrator initiates a payout request payload to a downstream processor:
{
"transaction_reference": "TXN-984392-NIP",
"amount": 150000,
"source_account": "0123456789",
"destination_account": "9876543210",
"destination_bank_code": "058"
} The source account is debited ₦150,000. The orchestrator calls the destination bank via the NIBSS Instant Payment (NIP) gateway. However, due to network latency on the telecommunications links, the connection times out.
The orchestrator receives a timeout exception. Because it cannot confirm the status of the instruction, the orchestrator retries the transaction. If the receiving bank does not check for transaction references to ensure idempotency, it processes the retry as a brand new instruction. The receiving bank credits the account a second time.
The sending bank only debited the source account once. The bank's end-of-day reconciliation jobs will eventually spot this mismatch, but that process takes 24 hours. Before the reconciliation runs, the customer has already withdrawn the double-credited funds via an ATM or spent them through a Point of Sale (POS) terminal.
The reverse-debit loop
Neobanks and mobile money operators often repeat a specific, disastrous sequence. The flow looks like this:
[Source Wallet] --(1. Debit ₦50,000)--> [Orchestrator]
[Orchestrator] --(2. Send NIP request)--> [NIBSS Switch]
[NIBSS Switch] --(3. Network Timeout)--> [Orchestrator]
[Orchestrator] --(4. Mark as Failed)--> [Source Wallet (Reversed)]
[NIBSS Switch] --(5. Delayed Execution)--> [Destination Bank (Credited)] The core design flaw is treating a network timeout as a definitive "failed" state. In distributed systems, a timeout is an unknown state. The NIP instruction may have reached NIBSS and successfully completed, or it may have been dropped.
By immediately reversing the source debit to maintain a fast user experience, the neobank creates a duplicate asset. The sender receives their refund, and the receiver receives the credited transfer. Both parties win, and the bank absorbs the direct financial loss.
What the real security implications are
Sophisticated fraud syndicates do not stumble onto these loopholes by accident. They actively monitor fintech APIs and banking apps for degraded performance signals. They track transaction latency and elevated error rates.
When they detect network degradation—often during paydays or periods of known NIBSS switch downtime—they launch coordinated transfer scripts. They send concurrent transaction streams specifically designed to trigger network timeouts. This behavior increases the probability of hitting unhandled Saga rollbacks, allowing them to exploit these logic flaws at scale before the platform can pause transfers.
How to build systems that do not have this problem
To prevent these losses, you must modify your architecture to handle distributed state correctly. Here is the fix:
Idempotency at every layer
Every service call must accept a unique correlation ID. If a network timeout occurs and the orchestrator retries, the downstream service must recognize the correlation ID and return the status of the existing transaction instead of executing a new one. Do not generate a new transaction ID for a retry.
Pessimistic balance locking before the external call
Never debit the source account after calling NIBSS or an external payment processor. Instead, implement pessimistic locking on the ledger row. Debit the source account first, placing the funds into a reserved state. Only commit or release the funds once you receive a definitive success or failure code.
Saga orchestrator with durable state
Do not manage Saga state in application memory. Use a database-backed, durable orchestrator like Temporal or a custom database-backed state log. If the application server crashes mid-transaction, the orchestrator can read the log and resume the compensating transaction.
Dead letter queues for failed compensations
When a compensating transaction fails, do not catch the exception and swallow it. Write the raw transaction payload to a dedicated Dead Letter Queue (DLQ) and trigger a high-priority pager alert to your engineering team. If a refund or a debit reversal fails, a human engineer must intervene immediately.
Reconciliation that catches both-sided success
Do not rely on API logs to confirm transaction status. Build automated reconciliation scripts that directly parse daily NIBSS settlement files. Match every processed transaction reference in the settlement report against your internal database records to find any discrepancies.
Automated scanners have no concept of distributed state machines or saga orchestration. This is found only through architecture review — reading orchestration code, reviewing retry logic, and tracing transaction flows across service boundaries.
Retrying successful NIP instructions
During a secure architecture review for a digital bank, we found their transfer orchestrator retried NIP instructions on any non-200 response—including on successful instructions that returned a 500 status code due to a response serialization bug on their end. The retry sent a second NIP instruction with a new reference. NIBSS processed both. The bank had been double-paying transfers intermittently for 3 months. The total unreconciled amount at the time of our review was ₦34 million. Fix priority: critical.
Is your transaction orchestrator handling network timeouts safely under load?
Get a security reviewFrequently asked questions
Does the CBN require Nigerian banks to have compensating transaction guarantees?
CBN's Risk-Based Cybersecurity Framework and its guidelines on IT infrastructure require banks to have data integrity controls. The specific technical requirement for Saga compensation is not spelled out but falls under 'transaction integrity' obligations.
How do we audit our current system for this?
Review every place in your codebase where you make an external call (NIBSS or Paystack) inside a function that also modifies your own database. Ask: if the external call succeeds but you crash before writing to your own database, what happens? If the answer is 'money is somewhere with no record', you have a Saga failure.
Are new-generation banks (neobanks) less likely to have this problem than traditional banks?
Ironically, the opposite is often true. Traditional banks have legacy monoliths that, while inflexible, are ACID compliant. Neobanks building on modern microservices architectures adopt distributed transaction patterns without always implementing the failure-handling they require.
Related reading
Blog: Business Logic Flaws in Nigerian Payment Platforms · Rate Limiting and Anti-Fraud Controls
Services: Secure Architecture Review · API Security Testing · Penetration Testing · Vulnerability Assessment