A password field may accept 100 characters while the authentication system verifies only the first 72, 64, or 20. The interface appears to accept the whole password, but the security decision does not.
That mismatch is password truncation: silently discarding part of a password before storing or verifying it. Truncation can make two visibly different passwords authenticate as the same credential. It can also create confusing migration bugs when one component preserves the full password and another shortens it.
The defensive rule is straightforward: define a reasonable maximum input length, reject passwords that exceed it, and verify every accepted password character. This article explains why that distinction matters, how truncation appears in real systems, and how to handle password-length limits without creating hidden equivalence.
The verifier should see the password the user chose
A password verifier answers a narrow question: does the submitted password match the credential established for this account?
The useful mental model is:
password accepted at enrollment
|
v
same complete value reaches password hashing
|
v
stored verifier
password submitted at login
|
v
same complete value reaches verification
|
v
match or rejectIf an application silently removes characters before hashing, the credential being verified is no longer the credential the user believes they chose.
Suppose a system keeps only the first eight characters. These two inputs then become equivalent to the verifier:
correct-horse
correct-treeBoth become correct- before verification. The example uses an intentionally tiny limit to make the problem visible; production limits are usually larger. The security principle is the same at any length: discarded characters contribute nothing to the authentication decision.
This does not mean applications must accept passwords of unlimited size. It means limiting input and truncating input are different operations.
Rejecting an oversized password is different from truncating it
A maximum password length can be a legitimate resource-control measure. Password hashing is intentionally expensive, and an application should not accept arbitrarily large request fields that consume unbounded memory or processing time.
Consider a system whose documented maximum is 128 characters.
A clear policy behaves like this:
length <= 128 -> accept the complete password
length > 128 -> reject with a validation errorA truncating policy behaves differently:
length <= 128 -> accept the complete password
length > 128 -> silently keep the first 128 charactersThe first policy preserves an important invariant: every accepted character participates in verification. The second policy creates classes of different strings that represent the same credential.
This distinction also improves usability. A user whose password manager generates a value beyond the supported limit receives an immediate error during password creation instead of discovering later that the application ignored part of the saved password.
Truncation creates hidden credential equivalence
The direct consequence of truncation is not that every password suddenly becomes easy to guess. The problem is more precise: characters beyond the truncation boundary provide no additional distinguishing value.
If a verifier keeps the first N characters, then any passwords with the same first N characters are equivalent from that verifier’s perspective.
That can matter in several ways.
First, users and password managers may believe a longer credential has been established when only a prefix matters. The effective credential is therefore different from the visible one.
Second, authentication behavior can become surprising. A mistyped suffix may still succeed, which hides the truncation and makes it harder to detect during normal use.
Third, migrations can break authentication. Imagine that an older service truncated passwords but a replacement service verifies complete values. Existing users may have enrolled a long password whose suffix was never part of the old verifier. The new service cannot infer what the old system discarded merely from the stored password hash.
The safest design is to avoid creating this ambiguity in the first place.
Find every place that can shorten the credential
The application form is only one layer. A password can be shortened before it reaches the password-hashing function by request parsing, validation code, database assumptions, legacy compatibility logic, or a wrapper around a cryptographic library.
Trace the value from enrollment and login to the actual password-verification API. The important question is not only, “How many characters does the UI allow?” It is:
Does every accepted password reach the verifier in full, through the same transformation rules at enrollment and authentication?
Keep password handling deliberately boring. Validate the supported length, apply only transformations that are part of the application’s documented password model, and pass the complete accepted value to a well-supported password-hashing implementation.
Do not trim leading or trailing spaces merely because ordinary text fields often receive that treatment. If spaces are valid password characters in your policy, silently removing them changes the credential. Similarly, avoid case folding or other generic text cleanup unless the authentication design explicitly defines that transformation and its consequences.
Unicode handling deserves particular care because character count, encoded byte length, and normalized representation are not the same thing. If the application accepts Unicode passwords, choose a consistent policy and make sure enrollment and verification apply it identically. Do not let different services independently invent normalization rules.
Library input limits need explicit handling
Some password-hashing implementations or algorithms have input-size behavior that developers can overlook. A wrapper may reject long inputs, a legacy interface may impose a limit, or an algorithm may have semantics that do not match the application’s password policy.
Do not respond by silently slicing every password to whatever size the current implementation accepts.
Instead, make the boundary explicit. If the chosen password-verification mechanism cannot faithfully process the application’s supported password range, either use a suitable supported mechanism or define and enforce a visible application limit that is compatible with it.
Be especially careful when changing password-hashing libraries. A migration should preserve the meaning of existing credentials. Test passwords near and beyond relevant boundaries before rollout rather than assuming two libraries treat long inputs identically.
The broader lesson is that a password policy and its verifier must agree. A front end that promises one limit while a back end implements another is a security-relevant inconsistency.
Test for full-password verification directly
Password truncation is easy to test without exposing real credentials.
In a test environment, create an account with a password whose length is comfortably within the application’s documented maximum. Then try a second password that is identical through a suspected boundary but differs afterward.
For example, if investigating a possible 64-character boundary, construct two synthetic test values with the same first 64 characters and different remaining characters. The second value must be rejected.
Also test the declared maximum itself:
maximum - 1 -> accepted
maximum -> accepted
maximum + 1 -> rejected clearlyThe exact boundary behavior should match the documented policy. Repeat equivalent tests through the real registration, password-change, password-reset, and login paths because shared assumptions are not guaranteed merely because the screens look similar.
If multiple services can verify the same account credential, run the boundary tests through each verifier. Inconsistent handling across services can create authentication failures or unexpected equivalence even when each component appears reasonable in isolation.
Plan carefully when a legacy system already truncates
Removing truncation from an existing system is not always a one-line fix. If historical password hashes were created from shortened inputs, the service usually cannot recover the discarded suffix from those hashes.
Treat this as a credential migration problem.
A practical strategy depends on what the existing verifier can determine and on the application’s risk tolerance. Systems may need to preserve legacy verification temporarily, mark credentials that require migration, and establish a new full-password verifier after a successful authentication or password change. In higher-risk situations, requiring a password reset may be more appropriate than maintaining ambiguous legacy behavior for a long period.
Do not silently reinterpret old hashes as if they had been created from complete passwords. Document the old semantics, test the transition, and make rollback behavior clear before deployment.
Migration code should also have an end state. Compatibility paths that remain indefinitely can turn a temporary weakness into permanent authentication behavior.
Understand what this control does not solve
Full-password verification protects the meaning of the credential: accepted characters are not silently discarded. It does not solve password security by itself.
It does not protect against phishing, credential reuse, malware on the user’s device, weak user-chosen passwords, an exposed password database, or unrestricted online guessing. Those threats require complementary controls such as compromised-password screening, appropriate password hashing, rate controls, multi-factor authentication where justified, and secure account recovery.
The threat model here is narrower: reduce security and migration failures caused by the verifier treating distinct accepted passwords as equivalent because part of the input was discarded.
A maximum length also remains appropriate when needed for resource safety. The important property is observable rejection rather than invisible modification.
Make the password boundary explicit
A reliable password system should be able to state its behavior simply: passwords within the supported range are processed completely; passwords outside that range are rejected rather than rewritten into a different credential.
That rule keeps the user interface, application policy, and verifier aligned. It also makes boundary tests meaningful and migrations easier to reason about.
When reviewing password handling, therefore, do not ask only whether the hashing algorithm is strong. Trace the complete password into that algorithm and verify that no layer silently removes information first. A strong verifier can only authenticate the value it actually receives.