Passwords test values

Passwords that registration and login read differently: cut after 72 bytes, trimmed, unnormalised or miscounted. 17 values, each with what it breaks and what a correct application does instead.

passwords version 1.0, updated 2026-11-04 CC-BY-4.0

Type them one at a time with AltShiftN in the palette, or take them all into a script with nkb emit passwords.

Step 1: register with 72 letters a and a 1

passwords/bcrypt-cut-register

pair 1 of 2 Two passwords that differ after byte 72

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1
  • 73 graphemes
  • 73 code points
  • 73 bytes
  • 73 UTF-16 units
What it breaks
Step 1 of the 72-byte test: register a new account with this password of 73 bytes. Newer libraries such as Go x/crypto, Spring Security and bcrypt 5 for Python refuse it, and an application that does not catch that shows an error page already here.
What a correct application does
Registered, or refused with a message that names the length limit.

Step 2: log in with 72 letters a and a 2

passwords/bcrypt-cut-login

pair 2 of 2 Two passwords that differ after byte 72

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2
  • 73 graphemes
  • 73 code points
  • 73 bytes
  • 73 UTF-16 units
What it breaks
Step 2: log in to the account from step 1 with this password, which differs only in its 73rd byte. A bcrypt hash that reads only the first 72 bytes, as in PHP, BCrypt.Net, jBCrypt, bcryptjs and pgcrypto, cannot tell the two apart.
What a correct application does
Login refused, because this is not the password the account was registered with.

Step 1: register with 36 Polish letters and a 1

passwords/bytes-not-chars-register

pair 1 of 2 Two Polish passwords that differ after byte 72

łłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłł1 łłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłł1
  • 37 graphemes
  • 37 code points
  • 73 bytes
  • 37 UTF-16 units
What it breaks
Step 1 of the same test in Polish: 37 characters, under any limit counted in characters, and 73 bytes in UTF-8, because each l with stroke takes two bytes.
What a correct application does
Registered.

Step 2: log in with 36 Polish letters and a 2

passwords/bytes-not-chars-login

pair 2 of 2 Two Polish passwords that differ after byte 72

łłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłł2 łłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłł2
  • 37 graphemes
  • 37 code points
  • 73 bytes
  • 37 UTF-16 units
What it breaks
Step 2: log in with this password, which differs only in its last character. A limit of 64 or 72 characters does not stop a hash that reads 72 bytes from cutting it.
What a correct application does
Login refused.

Step 1: register with a password that ends with a space

passwords/trailing-space-register

pair 1 of 2 Password with and without a trailing space

Secret-pass-42 Secret-pass-42\u0020
  • ends with a space
  • 15 graphemes
  • 15 code points
  • 15 bytes
  • 15 UTF-16 units
What it breaks
Step 1 of the trimming test: register with a password that ends with a space. A layer that trims input stores the password without it.
What a correct application does
Registered, with the space kept as part of the password.

Step 2: log in with the same password without the space

passwords/trailing-space-login

pair 2 of 2 Password with and without a trailing space

Secret-pass-42 Secret-pass-42
  • 14 graphemes
  • 14 code points
  • 14 bytes
  • 14 UTF-16 units
What it breaks
Step 2: log in with the password from step 1 without its last space, then once more with the space. Registration and login that trim differently let only one of the two in.
What a correct application does
Only the password with the space opens the account, or both do because both sides trim.

Step 2: log in with the same letters decomposed

passwords/nfc-nfd-login

pair 2 of 2 Composed and decomposed forms of one password

Zażółć-42 Zażółć-42
  • 9 graphemes
  • 12 code points
  • 16 bytes
  • 12 UTF-16 units
What it breaks
Step 2: log in with the same word written as base letters followed by combining accents. It looks identical, and hashing libraries take the bytes as given, so only an application that normalises the password lets it in.
What a correct application does
Login succeeds, because the password is normalised to NFC before it is hashed.

Sixteen spaces

passwords/spaces-only
16 ×
  • starts with a space
  • ends with a space
  • 16 graphemes
  • 16 code points
  • 16 bytes
  • 16 UTF-16 units
What it breaks
Passes a minimum length of 8, 12 or 15 characters and holds nothing a user could remember. A layer that trims input turns it into an empty password.
What a correct application does
Refused with the reason stated, or accepted and kept exactly, never trimmed to an empty password.

Four key emoji

passwords/emoji-four
🔑🔑🔑🔑 🔑🔑🔑🔑
  • 4 graphemes
  • 4 code points
  • 16 bytes
  • 8 UTF-16 units
What it breaks
Four characters that String.length in JavaScript, .NET and Java counts as eight, because each takes two UTF-16 units, while Python, PostgreSQL and NIST SP 800-63B count four. A page and a server written in different languages disagree about the minimum length.
What a correct application does
Counted as four characters on the page and on the server, and accepted or refused the same way by both.

Passphrase of 64 characters with spaces

passwords/passphrase-64
fourquietriverscarrysevenpaperboatspasttheoldmillgate four quiet rivers carry seven paper boats past the old mill gate
  • 64 graphemes
  • 64 code points
  • 64 bytes
  • 64 UTF-16 units
What it breaks
NIST SP 800-63B asks verifiers to accept at least 64 characters and the space, and a form with a maxlength of 20 or 32, or a rule against spaces, refuses the passphrase users are told to choose.
What a correct application does
Accepted in full, and the same passphrase opens the account afterwards.

Common password that meets the usual rules

passwords/composition-ok
Password1! Password1!
  • 10 graphemes
  • 10 code points
  • 10 bytes
  • 10 UTF-16 units
What it breaks
Has an upper-case letter, a digit and a symbol, so it passes the usual composition rules, and appears more than 500,000 times in the Pwned Passwords list of breached passwords.
What a correct application does
Refused as a common or breached password, with the reason stated.

Keyboard walk that meets the usual rules

passwords/breached-but-valid
Qwerty123! Qwerty123!
  • 10 graphemes
  • 10 code points
  • 10 bytes
  • 10 UTF-16 units
What it breaks
A keyboard pattern with a capital letter, digits and a symbol: it passes composition rules and appears more than 150,000 times in the Pwned Passwords list.
What a correct application does
Refused as a common or breached password, with the reason stated.

Password of 100 characters

passwords/login-maxlength
10 × Long-pass-
  • 100 graphemes
  • 100 code points
  • 100 bytes
  • 100 UTF-16 units
What it breaks
Registration accepts 100 characters while the login field has a lower maxlength, often 64, so the browser silently drops the rest and the user can never log in.
What a correct application does
The same password works on the registration, login and password change forms, or all three refuse it with the same limit stated.

Password in Cyrillic

passwords/cyrillic
пароль-42 пароль-42
  • 9 graphemes
  • 9 code points
  • 15 bytes
  • 9 UTF-16 units
What it breaks
NIST SP 800-63B asks verifiers to accept Unicode. A rule that allows only ASCII refuses it, or registration accepts it and an older layer in a single-byte encoding stores something else.
What a correct application does
Accepted, and the same password opens the account afterwards.

Password with angle brackets

passwords/angle-bracket
pass<word>42 pass<word>42
  • 12 graphemes
  • 12 code points
  • 12 bytes
  • 12 UTF-16 units
What it breaks
Request validation in ASP.NET on .NET Framework refuses a form value with a less-than sign followed by a letter, so a valid password ends at an error page.
What a correct application does
Accepted like any other printing ASCII character.

Password with a plus and a percent sign

passwords/plus-and-percent
Pa+ss%41-42 Pa+ss%41-42
  • 11 graphemes
  • 11 code points
  • 11 bytes
  • 11 UTF-16 units
What it breaks
In a form-encoded body a plus means a space and %41 means A. A client that builds the body by hand without encoding sends Pa ssA-42, so the page and that client store different passwords.
What a correct application does
Stored and checked exactly as typed, through every client.

Pairs

Each pair is two of the values above, worth typing side by side: into two fields, or into one field twice. AltShiftN types them in turn, and the palette says which half of a pair comes next.

Two passwords that differ after byte 72

passwords/bcrypt-cut
identity

pair 1 of 2 Step 1: register with 72 letters a and a 1

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1
  • 73 graphemes
  • 73 code points
  • 73 bytes
  • 73 UTF-16 units

pair 2 of 2 Step 2: log in with 72 letters a and a 2

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2
  • 73 graphemes
  • 73 code points
  • 73 bytes
  • 73 UTF-16 units
What it breaks
Step 3 of the 72-byte test: if the second password opened the account, the system hashes only the first 72 bytes and two different passwords open it. An error page at step 1 means the library refuses long passwords and the application does not handle it.
What a correct application does
Login with the second password refused, and registration with the first accepted or refused with the limit stated.

Two Polish passwords that differ after byte 72

passwords/bytes-not-chars
identity

pair 1 of 2 Step 1: register with 36 Polish letters and a 1

łłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłł1
  • 37 graphemes
  • 37 code points
  • 73 bytes
  • 37 UTF-16 units

pair 2 of 2 Step 2: log in with 36 Polish letters and a 2

łłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłłł2
  • 37 graphemes
  • 37 code points
  • 73 bytes
  • 37 UTF-16 units
What it breaks
Step 3: if the second password opened the account, the length check counts characters while the hash counts bytes, so a password in Polish, Cyrillic or Chinese is cut far earlier than its length suggests.
What a correct application does
Login with the second password refused.

Password with and without a trailing space

passwords/trailing-space
identity

pair 1 of 2 Step 1: register with a password that ends with a space

Secret-pass-42
  • 15 graphemes
  • 15 code points
  • 15 bytes
  • 15 UTF-16 units

pair 2 of 2 Step 2: log in with the same password without the space

Secret-pass-42
  • 14 graphemes
  • 14 code points
  • 14 bytes
  • 14 UTF-16 units
What it breaks
Step 3: if only one of the two logins works and it is not the one with the space, registration and login trim differently, and a user who set the space is locked out.
What a correct application does
Only the password with the space opens the account, or both do because both sides trim.

Composed and decomposed forms of one password

passwords/nfc-nfd
identity

pair 1 of 2 Step 1: register with composed Polish letters

Zażółć-42
  • 9 graphemes
  • 9 code points
  • 13 bytes
  • 9 UTF-16 units

pair 2 of 2 Step 2: log in with the same letters decomposed

Zażółć-42
  • 9 graphemes
  • 12 code points
  • 16 bytes
  • 12 UTF-16 units
What it breaks
Step 3: NIST SP 800-63B asks verifiers to normalise passwords to NFC. Without it, the same password typed on one system and pasted from another does not match.
What a correct application does
Both forms open the account.