Skip to content

Iban accepts an invalid IBAN ending in "\n" and rejects a valid one with the same newline (regex $ matches before a trailing newline) #311

Description

@matt-edmondson

What's wrong

IsIbanAttribute's validator checks ^[A-Z]{2}[0-9]{2}[A-Z0-9]+$ (Semantics.Strings.Identifiers/IsIbanAttribute.cs:24). In .NET, $ without RegexOptions.Multiline also matches just before a final \n, so a value with a trailing newline passes the structural check.

Iban.MakeCanonical (Semantics.Strings.Identifiers/Iban.cs:21) strips only ' ', so the newline reaches the validator. The length gate (15–34) allows the extra character. PassesMod97 then feeds '\n' through ApplyChar as if it were a letter: c - 'A' + 10 gives −45. Whether the value passes then depends on the check digits, not on whether the IBAN is valid.

Reproduction (run against the built assembly)

Iban.Create<Iban>("GB67WEST12345698765432\n") -> ACCEPTED, stored as "GB67WEST12345698765432\n" (length 23)
Iban.Create<Iban>("GB67WEST12345698765432")   -> ArgumentException  (GB67 is not a valid IBAN)
Iban.Create<Iban>("GB82WEST12345698765432")   -> ACCEPTED           (the valid reference IBAN)
Iban.Create<Iban>("GB82WEST12345698765432\n") -> ArgumentException  (valid IBAN rejected)

Why it matters

  • A value with wrong check digits validates, and its stored canonical form contains a control character.
  • A valid IBAN pasted with a trailing newline, which is common from text areas and files, is rejected with a misleading "mod-97 checksum failed".
  • The identifiers spec (docs/superpowers/specs/2026-07-01-concrete-semantic-strings-design.md) says canonicalization strips whitespace, but only spaces are stripped.

The same $ anchor appears in IsUuidAttribute.cs:23 and IsUlidAttribute.cs:23. Uuid and Ulid are protected today only because their MakeCanonical calls Trim(). The attributes are public, so a consumer type that uses them without trimming would inherit the hole.

Suggested fix / acceptance criteria

  • Anchor the identifier patterns with \z (or \A…\z) instead of $.
  • Make Iban.MakeCanonical strip all whitespace (char.IsWhiteSpace), as the spec says, so that "GB82 WEST 1234 5698 7654 32\n" canonicalizes to GB82WEST12345698765432 and validates.
  • Tests:
    • an invalid IBAN with a trailing \n is rejected;
    • a valid IBAN with a trailing \n or \t canonicalizes and validates;
    • [IsUuid] / [IsUlid] on a type that doesn't trim reject a trailing \n.

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions