GHSA-mv2c-jwm9-pfrq
Sanctions screening is bypassed by single-character perturbations inside sanctioned names
Impact
Sanctions screening in qwed-finance (sanctions_match / normalize_for_screening, used by CrossGuard.verify_swift_with_sanctions and UCPIntegration.verify_iso20022_payment) can be bypassed by changing a single character inside a sanctioned name. A payment to a sanctioned party passes screening when the name is perturbed in ways a human reader — or a payment operator — would still read as the same party.
Reproduced on v3.0.0 with sanctions list ["EVIL CORP"] and the name in the MT103 :59: beneficiary field:
| Beneficiary name | Result |
|---|---|
EVIL CORP |
blocked (control) |
EV-IL CORP |
passed |
E.V.I.L. CORP |
passed |
ÉVIL CORP |
passed |
EVıL CORP (dotless i) |
passed |
small-capital letters ᴇᴠɪʟ ᴄᴏʀᴘ |
passed |
Who is affected: applications that use qwed-finance sanctions screening on SWIFT MT or ISO 20022 messages generated by an LLM or another untrusted source. The npm SDK does not expose these code paths.
Root cause
normalize_for_screening maps every non-alphanumeric character to a space, so punctuation inside a word splits it into separate tokens (EV IL), which no longer contain the sanctioned token. Diacritics are not folded, and Latin look-alike letters that NFKC does not fold (small capitals, dotless i) are neither normalized nor flagged by the mixed-script check.
Patches
Fixed in qwed-finance 3.0.1 (release). Upgrade with pip install -U qwed-finance==3.0.1.
normalize_for_screening now:
- folds diacritics and stray combining marks (NFKD followed by mark removal);
- maps Latin look-alike letters (small capitals, dotless i) and common Cyrillic/Greek homoglyphs to a Latin skeleton.
sanctions_match additionally compares separator-free forms in the forward direction, so punctuation or spacing inserted inside a word no longer splits the sanctioned name. Address fragments remain forward-only. Transliterations and true aliases still require alias-structured list data.
Workarounds
- Additionally compare names with all non-alphanumeric characters removed (not replaced with spaces).
- Fold diacritics (NFKD and drop combining marks) and apply a confusables skeleton (Unicode TR39) to both sides before matching, or route any name that changes under these folds to manual review.
- Do not treat a
passedsanctions result from affected versions as a sole control.
References
Reproduced on qwed-finance 3.0.0 (bb0cdf3).