Skip to content

electronicFormatIBAN() maps non-ASCII characters into A-Z, so isValidIBAN() accepts strings that are not IBANs #690

Description

@kinu01

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions