Skip to content

Weak password requirements

CWE-521OWASP A07:2021Updated September 4, 20265 min read

An application that permits short passwords or does not block known leaked passwords makes guessing and reuse profitable. The classic complexity rules with capitals and punctuation work against you: they lead to predictable patterns. Length, a blocklist and a second factor are what make the difference.

Few security topics have shifted as thoroughly in recent years as password policy. The rules most applications still work with, minimum eight characters, a capital, a digit, change every quarter, are regarded by current guidance not merely as outdated but as harmful. What takes their place is better supported by the evidence.

What are weak password requirements?

Weak password requirements are rules that do too little to stop users choosing a password that is easy to guess or already known from earlier data breaches. In practice this usually means a minimum length that is too low, the absence of a check against known leaked passwords, or allowing passwords equal to the username or the company name.

At the same time there is a less obvious side. Rules that enforce complexity, at least one capital, one digit, one punctuation mark, barely raise security and sometimes lower it. People respond to such requirements with predictable patterns: Welcome2026! satisfies every complexity rule and appears in every wordlist an attacker uses.

Compare it with a lock whose owner is required to choose a key with a set number of grooves. The number of theoretical possibilities rises, but because everyone picks the same shape, the burglar only has to try a handful of keys. What counts is not how complicated the password looks, but how genuinely unpredictable it is.

What does a sensible policy look like?

Vulnerable:

function passwordIsValid(password) {
  return password.length >= 8
    && /[A-Z]/.test(password)
    && /[a-z]/.test(password)
    && /[0-9]/.test(password)
    && password.length <= 16;        // and no longer
}

This check approves Summer24! and rejects the cat jumped over the blue fence. That is precisely the wrong way round: the first appears in virtually every list of common passwords, while the second has considerably more entropy. The maximum length of sixteen characters is a bad sign too, because with a correctly hashed password there is no reason to restrict the length so tightly.

Safe:

async function passwordIsValid(password, user) {
  if (password.length < 12 || password.length > 128) return false;

  // No password derived from the user's own details
  const own = [user.email.split('@')[0], user.name, 'assistsec'];
  const lower = password.toLowerCase();
  if (own.some((t) => t && lower.includes(t.toLowerCase()))) return false;

  // Known from earlier breaches or commonly used
  if (await onBlocklist(password)) return false;

  return true;
}

// Check with k-anonymity: the password never leaves your environment
async function onBlocklist(password) {
  const hash = sha1(password).toUpperCase();
  const response = await fetch(`https://api.pwnedpasswords.com/range/${hash.slice(0, 5)}`);
  const tail = hash.slice(5);
  return (await response.text()).split('\n').some((r) => r.startsWith(tail));
}

The emphasis has shifted. The minimum length rises to twelve characters, the maximum length is generous enough to allow passphrases, and there are no complexity rules left to provoke patterns. Instead, what actually matters is checked: has this password already been leaked, and is it traceable to the user themselves? For the blocklist check, only the first five characters of the hash are sent, so the password itself does not leave your environment.

Allow pasting in the password field and do not block it “for security”. Preventing pasting makes password managers impractical and pushes users towards short, hand-typed and therefore weaker passwords. Show a strength indicator instead of a list of rules.

What is the impact of a weak password policy?

The severity usually stays low to medium, because a weak policy grants no access by itself. It determines how likely it is that an attack on authentication succeeds.

Two forms of attack benefit directly. In password spraying, an attacker tries one common password across many accounts; the more users were allowed to choose a predictable password, the greater the chance one hits. In credential stuffing, combinations from earlier breaches are reused; without a blocklist, a user can choose exactly the password that has already leaked elsewhere.

What increases the risk is that a successful attack here yields full access, with all the account’s rights and without anything unusual having to appear in the logs. If it concerns an administrator account, the impact is on the whole system. And because people reuse passwords between services, a breach at your organisation also affects those users’ accounts elsewhere, which is a reputational matter as well as a security one.

How do you detect a weak password policy?

A tester tries which values are accepted at registration and when changing a password. Is a password of eight characters allowed? Can Welcome2026! be chosen? And the username itself, or the name of the organisation? That quickly gives a picture of the real lower bound.

Next they check whether the rules are enforced on the server or only in the browser. A check that exists solely in JavaScript can be bypassed with one direct request, which is a common finding. They also test whether the requirements are the same at registration, at password reset and when changing from the profile, because those three routes are often implemented separately and then differ in strictness. Beyond that they assess whether a blocklist is used, whether pasting is allowed, and whether a maximum length points to an implementation problem. AssistSec always assesses the policy together with the presence of a second factor and limits on login attempts, because those three jointly determine how resilient authentication really is.

How do you prevent a weak password policy?

  • Set a minimum length of at least twelve characters, and preferably more for administrator accounts.
  • Drop complexity rules; they lead to predictable patterns without real gain.
  • Check every new password against a blocklist of leaked and commonly used passwords.
  • Reject passwords derived from the username, the email address or the name of your organisation.
  • Allow a generous maximum length (64 to 128 characters) and accept spaces and all special characters.
  • Allow pasting, so password managers stay usable.
  • Do not enforce periodic change; only ask for a new password on a concrete indication of compromise.
  • Enforce all rules on the server, not only in the browser, and on every route where a password is chosen.
  • Combine the policy with two-factor authentication and a limit on login attempts.

Sources

Frequently asked questions

Should I make passwords expire periodically?

No, that advice has been dropped. Forced periodic change demonstrably leads to weaker passwords, because users make small predictable adjustments such as an incrementing digit. Only ask for a change when there is a concrete indication of compromise.

Why are complexity rules counterproductive?

Because people respond to them with patterns. Requiring a capital, a digit and a punctuation mark produces passwords en masse that start with a capital and end in a digit and an exclamation mark. Attackers know those patterns and apply them, so the theoretical gain evaporates in practice.

How do I check for leaked passwords?

With a blocklist of known leaked and commonly used passwords, checked at the moment the user chooses one. Services exist that do this with k-anonymity, where you send only the first characters of the hash and the full password never leaves your environment.

Should I set a maximum length?

Only a generous one, to prevent overload; 64 to 128 characters is common. A low maximum length or a ban on spaces and special characters is a strong signal that the password is not being hashed correctly, because with a good hash function the length of the input is irrelevant.

Related articles

Press / to search · Esc