Why name matching exists in the first place
The CBN's AML/CFT framework — codified in the CBN AML/CFT/CPF Regulations 2022 — requires that financial institutions take reasonable steps to ensure that funds entering a customer's wallet or account are traceable to that customer's verified identity. In practice, this means a user whose BVN ties them to the name JOHN ADEYEMI should not be able to fund their wallet from a card or bank account belonging to BLESSING OKAFOR.
The intent is sound: close the channel that money mule networks exploit to move proceeds through legitimate-looking wallets. The implementation, however, is a different conversation. Most fintechs bolt on a name matching step that calls NIBSS for account name resolution, compares the returned string against the BVN name on file, and applies a similarity threshold. That chain has at least four exploitable weak points.
How the typical implementation works
The standard flow across Nigerian fintechs looks roughly like this:
- User initiates a funding event — card, bank transfer, or direct debit.
- Backend calls the NIBSS NIP Name Enquiry API with the source account number and sort code. NIBSS returns an account name string, e.g.,
"ADEYEMI JOHN OLUWASEUN". - Backend retrieves the user's registered name from the internal BVN record, e.g.,
"JOHN ADEYEMI". - A similarity function — commonly Levenshtein distance, Jaro-Winkler, or a plain
String.includes()— is run against both strings. - If the similarity score exceeds a configured threshold (often 70–80%), the funding proceeds. Below threshold, it is blocked or queued for review.
Each of these steps introduces attack surface. The name enquiry returns whatever the bank registered — which is not necessarily what NIBSS holds as the BVN name. The similarity function operates on raw strings. And the threshold is almost always tuned to reduce false positives for legitimate users, which also widens the window for attackers.
Bypass technique 1: Title injection
BVN records frequently include honorifics. A doctor registered through a first-generation bank may appear in NIBSS as DR JOHN ADEYEMI. An attacker who knows or guesses the target name structure can register with a title variant — say, MR ADEYEMI JOHN — and fund from a mule account held as ADEYEMI JOHNSON.
The Levenshtein distance between ADEYEMI JOHN and ADEYEMI JOHNSON is 3 characters (add "SON"). Against a 20-character string, that is an 85% similarity score — well above most thresholds. A naive String.includes() check is even more permissive: if the BVN name DR JOHN ADEYEMI is tested for whether it includes the account name substring JOHN, it passes immediately, regardless of what follows.
Nigerian naming conventions make this worse. Common surnames — Adeyemi, Okafor, Eze, Bello, Ibrahim — appear across hundreds of thousands of accounts. Any implementation that checks for substring presence rather than full-string similarity will produce a massive false-positive rate that attackers can exploit at scale.
Bypass technique 2: Middle name omission and abbreviation
BVN records often carry three names: CHUKWUEMEKA ONYEKWERE OKAFOR. Many bank accounts, particularly those opened at old-generation banks with character limits, store the same person as C.O. OKAFOR or CHUKWUEMEKA OKAFOR. Legitimate users experience this mismatch daily, so fintechs tune their thresholds to accommodate it.
An attacker who controls a mule account registered as C. OKAFOR can fund a wallet registered under a different OKAFOR entirely. The Jaro-Winkler score between CHUKWUEMEKA ONYEKWERE OKAFOR and C OKAFOR varies significantly depending on how the algorithm handles prefix weighting — but against a poorly chosen threshold, it may still pass. If the fintech also strips periods and spaces before comparison (a common normalization step), C.O. OKAFOR becomes COOKAFOR, which Levenshtein scores very differently again.
The inconsistency across Nigeria's banking infrastructure — Polaris Bank, Heritage Bank era accounts, co-operative society accounts, microfinance banks — means an attacker has a large surface of account name formats to experiment with before finding one that passes the threshold.
Bypass technique 3: Unicode character substitution
This is the most technically deliberate bypass. Unicode contains visually identical characters across different code blocks. The Latin lowercase a (U+0061) and the Cyrillic а (U+0430) are indistinguishable on most screens but produce completely different byte sequences. An attacker who controls the name they register with can substitute one or more characters with their homoglyphs:
АBUBAKAR(Cyrillic А at position 0) vsABUBAKAR(Latin A) — renders identically, byte-differs entirely.EMEKА(Cyrillic А at the end) vsEMEKA— same visual output, different string.- Mixed-script names can cause similarity algorithms to return 0% match on an otherwise identical string.
The attack direction here is usually the opposite of the others: instead of making a different name score high, the attacker makes a genuinely matching name score low — then argues the block is a bug. More practically, it can be used to poison name records during onboarding, creating an account whose stored name will never cleanly match NIBSS output, giving the attacker a persistent bypass vector for all future funding events.
Bypass technique 4: Case and diacritic manipulation
Many Nigerian names of Yoruba or Hausa origin carry diacritics in their proper orthography: Àbúbàkàr, Adéyẹmí, Ọlọ́rundárè. Banks typically strip these at account opening, but if the BVN record was created by a system that preserved them and the comparison system does not normalize Unicode before comparison, you have a guaranteed mismatch.
An attacker onboarding through a fintech that does normalize will register as ADEYEMI. They then fund from an account whose name is stored by their bank as Adéyẹmí. If the fintech's comparison function operates on raw Unicode strings without NFKC normalization, the Levenshtein distance between ADEYEMI and Adéyẹmí could be 4 or more substitutions, dropping the score below threshold. The funding is blocked — but the attacker now has a documented "false block" they can use to complain to customer support and get manual override.
The diacritic manipulation path is less about automated bypass and more about social engineering the review process. Manual review agents who see a plausible name and a customer complaint will often approve the transaction.
Business impact: this is an AML failure, not just a UX bug
When a name matching bypass succeeds, the fintech has processed a third-party-funded transaction that its AML controls were explicitly designed to block. The downstream consequences compound:
- NFIU reporting gaps: Transactions that should appear as suspicious activity reports (SARs) are instead processed as normal peer-to-peer transfers. The Nigerian Financial Intelligence Unit receives a clean transaction record.
- CBN examination findings: During routine AML examinations, the CBN reviews a sample of high-value transactions against name match logs. A pattern of near-threshold approvals from mismatched names is a Category A finding under the CBN AML/CFT framework, carrying fines from ₦10 million to ₦2 billion depending on severity and history.
- NDPA exposure: If the bypass involves presenting another person's identity data to pass the check, the fintech has potentially processed a transaction using another individual's PII without consent — an NDPA violation on top of the AML breach.
- Investor and licensing risk: Fintechs applying for payment service bank licenses or seeking Series A investment with undisclosed AML control gaps face term sheet renegotiation or license rejection once the finding surfaces in technical due diligence.
Money mule networks operate at scale. A bypass that works once works thousands of times before it is detected — if it is detected at all. A fintech processing ₦500 million monthly through a flawed name match layer may not know how much of that volume is third-party-funded until an NFIU audit surfaces the anomaly.
The fix: normalize first, compare second, verify with BVN third
Name matching should be one layer in a defense stack, not the only layer. The implementation changes required are straightforward:
Step 1 — Normalize both strings before any comparison
Every name string — both the NIBSS-returned account name and the user's stored BVN name — must go through the same normalization pipeline before comparison. Here is a production-ready Node.js function:
function normalizeName(name) {
const titles = [
'MR', 'MRS', 'MISS', 'MS', 'DR', 'PROF',
'ENGR', 'ALHAJI', 'ALHAJA', 'CHIEF', 'PASTOR',
'REV', 'ELDER', 'DEACON', 'DEACONESS', 'BARR',
];
// 1. Uppercase
let n = name.toUpperCase();
// 2. Unicode normalization — NFKC collapses compatibility variants
// and decomposes then recomposes diacritics consistently
n = n.normalize('NFKC');
// 3. Strip diacritics by decomposing and removing combining marks
n = n.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
// 4. Remove anything that is not A-Z or space
n = n.replace(/[^A-Z ]/g, '').trim();
// 5. Strip title prefixes as whole words
titles.forEach((t) => {
n = n.replace(new RegExp('\\\\b' + t + '\\\\b', 'g'), '').trim();
});
// 6. Collapse multiple spaces
return n.replace(/\s+/g, ' ');
}
// Usage
const nibssName = normalizeName('DR. ADÉYẸMÍ JOHN'); // => 'ADEYEMI JOHN'
const bvnName = normalizeName('JOHN ADEYEMI'); // => 'JOHN ADEYEMI'
Note that after normalization, token-order differences still matter. ADEYEMI JOHN and JOHN ADEYEMI normalize identically in terms of characters but differ in token order. Your similarity function should compute the score on both the original normalized order and a token-sorted variant, then take the higher of the two. This handles the very common Nigerian naming convention where surname-first and forename-first orderings are used interchangeably across institutions.
Step 2 — Use a layered threshold with mandatory BVN verification
Name similarity alone should never be the approval gate for funding events. The correct architecture is:
- BVN-to-BVN match (mandatory for transfers above ₦50,000): Use the NIBSS BVN Validation API to confirm that the BVN linked to the source bank account matches the user's BVN on file. If they differ, block regardless of name similarity score.
- Similarity ≥ 95%: auto-approve (after passing BVN check).
- Similarity 80–94%: flag for near-real-time review — allow the transaction to complete but queue it for AML review within 24 hours.
- Similarity < 80%: block and require user confirmation — present the name mismatch to the user, capture their explicit acknowledgment, log with timestamp and device fingerprint, and flag for manual review.
Never auto-approve anything below 95% normalized similarity without BVN confirmation. The CBN examination teams know to look at the 80–94% band when reviewing name match logs.
Step 3 — Validate incoming name strings for homoglyph attacks
Before storing any user-supplied name at onboarding, run a script detection check. The Intl.Segmenter API and Unicode script property can identify strings that mix Latin with Cyrillic, Greek, or other look-alike scripts:
function containsMixedScripts(str) {
// Detect characters outside Basic Latin and Latin Extended blocks
// Used to catch Cyrillic/Greek homoglyph substitutions
const suspiciousChar = /[^\u0000-\u024F\s]/;
return suspiciousChar.test(str);
}
function rejectHomoglyphName(name) {
if (containsMixedScripts(name)) {
throw new Error('Name contains characters outside expected Latin range. Registration rejected.');
}
}
This is a simple first gate. For a more robust implementation, check that every code point in the name string belongs to the Latin script using the Unicode Script property. Reject registration if any character does not pass.
Step 4 — Audit log every name comparison, not just failures
Your AML evidence trail needs the full picture. For each funding event, log: the raw NIBSS name, the raw BVN name, both normalized forms, the similarity score, the threshold applied, the decision taken, and whether BVN verification was performed. Store this for a minimum of five years per CBN record-keeping requirements. During an NFIU audit, the absence of this log is itself a finding.
Digital bank with .includes() name check — first name substring bypass
During a security review of a CBN-licensed digital bank, we found the entire name matching system reduced to a single JavaScript condition: accountName.toLowerCase().includes(userFirstName.toLowerCase()). If the account name returned by NIBSS contained the user's first name anywhere in the string, the funding was permitted. A user registered as ADE SMITH could fund their wallet from any account with "ADE" in the name — including ADEGBOYEGA ENTERPRISES LTD or ADEOLA AMUSAN TRADERS. No BVN check was performed. No threshold existed. The check had been introduced as a "quick fix" for legitimate mismatch complaints six months earlier and was never revisited. Fix priority: high. Resolution: full normalization pipeline, Jaro-Winkler similarity at 0.92 threshold, mandatory BVN-to-BVN verification for all funding events above ₦10,000.
Does your funding flow validate BVN-to-BVN, or is it still relying on a similarity score against a raw name string?
Get a security reviewFrequently asked questions
Does NIBSS provide BVN verification as part of name enquiry?
NIBSS NIP name enquiry returns the account name but not the BVN. To get BVN-to-account linkage, fintechs use the NIBSS BVN validation API separately, which is the correct gate for high-value AML checks.
What similarity threshold is safe for name matching?
No threshold is universally safe. A similarity score must be combined with a BVN match. If the BVN matches, name matching becomes a secondary confirmation, not the primary gate. Relying on a score alone invites the bypass techniques described in this article.
How should we handle legitimate name mismatches?
Present the mismatch to the user, require them to confirm it is intentional, log the decision with their confirmation timestamp and device fingerprint, and flag it for manual AML review above certain transaction sizes. Never silently auto-approve.
Related reading
Blog: KYC and BVN data security in Nigerian fintech
Services: API security testing · Mobile money security
Guides: CBN compliance and security