electronicFormatIBAN() uses String.prototype.toUpperCase(), which applies full Unicode case mapping. Several non-ASCII characters map into A-Z, and some turn one character into two:
'fi'.toUpperCase() // 'FI'
'ß'.toUpperCase() // 'SS'
'ı'.toUpperCase() // 'I'
Because isValidIBAN() does not normalise its own input, it trusts whatever electronicFormatIBAN() hands it. Using the two-line flow from the README:
const ibantools = require('ibantools');
ibantools.isValidIBAN(ibantools.electronicFormatIBAN('fi2112345600000785'));
// true <-- 17 characters, and U+FB01 is not an IBAN character
ibantools.isValidIBAN(ibantools.electronicFormatIBAN('Fı2112345600000785'));
// true <-- U+0131 DOTLESS I
ibantools.isValidIBAN(ibantools.electronicFormatIBAN('GB77ßBK60161331926819'));
// true <-- 21 characters, U+00DF expands to SS
ibantools.isValidIBAN(ibantools.electronicFormatIBAN('GB66fiBK60161331926819'));
// true
ibantools.isValidIBAN(ibantools.electronicFormatIBAN('GB48NWıK60161331926819'));
// true
Verified on 4.5.4 and on current master.
ISO 13616 permits only digits and the 26 Latin capitals, so none of these inputs is an IBAN. The ligature cases also change the length, so a 17 character string is accepted as an 18 character Finnish IBAN.
Why this matters in practice: a common pattern is to validate the user's raw input and then store that raw input. PDF text often encodes "fi" as U+FB01, and copying an IBAN out of a PDF invoice is a normal thing for a user to do. The value that gets stored is then a string no payment rail can parse, and it passed validation.
Suggested fix: uppercase ASCII only, so a character outside the IBAN set survives to be rejected by the country's BBAN pattern.
return iban.replace(/[-\ ]/g, '').replace(/[a-z]/g, (char) => char.toUpperCase());
This is the same ordering the iban package uses (it strips non-alphanumerics before uppercasing). I checked iban, iban-ts and validator and none of them accept these inputs.
I have a branch with this fix plus regression tests, npm run all passing and coverage unchanged. Happy to open a PR if you would like it.
electronicFormatIBAN()usesString.prototype.toUpperCase(), which applies full Unicode case mapping. Several non-ASCII characters map intoA-Z, and some turn one character into two:Because
isValidIBAN()does not normalise its own input, it trusts whateverelectronicFormatIBAN()hands it. Using the two-line flow from the README:Verified on 4.5.4 and on current master.
ISO 13616 permits only digits and the 26 Latin capitals, so none of these inputs is an IBAN. The ligature cases also change the length, so a 17 character string is accepted as an 18 character Finnish IBAN.
Why this matters in practice: a common pattern is to validate the user's raw input and then store that raw input. PDF text often encodes "fi" as U+FB01, and copying an IBAN out of a PDF invoice is a normal thing for a user to do. The value that gets stored is then a string no payment rail can parse, and it passed validation.
Suggested fix: uppercase ASCII only, so a character outside the IBAN set survives to be rejected by the country's BBAN pattern.
This is the same ordering the
ibanpackage uses (it strips non-alphanumerics before uppercasing). I checkediban,iban-tsandvalidatorand none of them accept these inputs.I have a branch with this fix plus regression tests,
npm run allpassing and coverage unchanged. Happy to open a PR if you would like it.