Glossary

What is a salt? The random per-user value added when hashing passwords

A salt is a random per-user value added before a password is hashed. Why it defeats rainbow tables and bulk cracking, and how it differs from a pepper.

Published 2026-06-27 Updated 2026-10-06 8 min read
On this page

"Salt" comes up the moment you talk about password hashing. Adding one random value before hashing changes the security picture dramatically. Here's how it works and the key points (no attack steps).

Why a salt makes passwords safer

Without a salt, users with the same password get the same stored hash. That gives an attacker two options: look up the password directly in a precomputed table (a rainbow table), and reuse the result of cracking one account for everyone with the same password.

Add a salt and the same "password123" stores as something completely different for each user.

No salt: "password123" → same hash for all (a lookup table finds it instantly)
↓ add a per-user salt
Alice: salt_a + password123 → hash X
Bob: salt_b + password123 → hash Y (≠ X)
Same password, different salts → different stored values for everyone. Precomputed tables stop working.

For the same reason, a salt must be generated fresh per user (ideally per password). If everyone shares one salt, users with the same password end up with matching stored values again, and most of the benefit is lost. Use a hard-to-predict cryptographic random number generator, and store the salt alongside the hash (it doesn't need to be secret).

A salt only protects against precomputed tables and bulk cracking of reused passwords. Slowing down a brute-force attack on a single password is not its job; that's handled by a deliberately slow hash such as bcrypt/Argon2. They cover different threats, so always use both.

Salt length and how to generate it

Two documents set the baseline:

  • NIST SP 800-63B-4 (the US authentication guideline): the salt must be at least 32 bits and chosen so that stored salts rarely collide. Both the salt and the hash are stored for each password
  • RFC 9106 (the Argon2 specification): 16 bytes (128 bits) is recommended for password hashing, reducible to 64 bits where space is tight

Three rules for generating it:

  • Use a cryptographic random number generator. Use your language's secure random function, not predictable ones like Math.random() or PHP's mt_rand()
  • Don't use guessable values: a username, email address, user ID, or sign-up time is not a substitute for a salt
  • Generate a new salt when the password changes. Keeping the old one leaves a link between old and new hashes

In practice, standard bcrypt, Argon2, and scrypt implementations meet all of this automatically. If you're writing code that creates salts yourself, treat that as a sign to review it.

Salt vs pepper vs key stretching

Password storage involves three similarly named measures. They defend against different things, so none replaces another.

SaltPepperKey stretching (slow hashing)
What it isA random value per userA secret value shared across all usersMaking the hash computation deliberately expensive
Secret?No (stored with the hash)Yes (kept outside the database)Settings don't need to be secret
Defends againstPrecomputed tables, bulk cracking of identical passwordsCracking when only the database leaksBrute force on each hash
ImplementationAdded automatically by bcrypt/Argon2Added by you if neededbcrypt cost, Argon2 memory and iterations

NIST SP 800-63B-4 recommends that a "secret key known only to the verifier" (what's usually called a pepper) be stored separately from the password hashes, ideally inside dedicated hardware such as an HSM.

Real case: unsalted storage at LinkedIn (2012)

In June 2012, about 6.5 million password hashes said to belong to LinkedIn users were reported to have been posted online. LinkedIn confirmed that some of them corresponded to LinkedIn accounts and disabled the affected members' passwords.

On its official blog, the company said it had been moving from a system that only hashed passwords to one that both hashed and salted them. At the time, experts quoted in the press criticized the company for protecting passwords with SHA-1 hashing alone.

Two lessons:

  • Unsalted hashes let common passwords be recovered in bulk from precomputed tables
  • Even mid-migration, if hashes in the old format remain, a leak's impact is decided by that old format

How to check your own environment

1

Look at the shape of the stored strings

In a development database you control, look at a few password values. For bcrypt, the 22 characters after $2b$12$ are the salt. For Argon2, $argon2id$v=19$m=…,t=…,p=…$ is followed by the salt and the hash separated by $. If the value matches neither shape and there is no separate salt column, the passwords may be stored without a salt.

2

Create two test accounts with the same password

In a development environment, register two test accounts with the same password and compare the stored values. If they match, the salt isn't working. Also confirm the salt part changes when a password is changed.

3

Look for code that builds salts by hand

Search the code for the word salt and for places that combine random or hash functions by hand. If you find a predictable random function, a reused username or ID, or a fixed string, replace it with your language or framework's standard password function.

4

Use the practical guide for migration

How to migrate away from unsalted storage (such as rehashing at login) and the recommended settings for each algorithm are covered in how to store passwords safely.

Common misconceptions vs the truth

Misconception

  • A salt must be kept secret
  • One shared salt for all users is fine
  • A salt makes even weak passwords safe

The truth

  • A salt can be public (store it with the hash)
  • A different random value per user (ideally per password)
  • A salt defends "precomputation and reuse cracking"; brute force is handled by a slow hash

This site's view: get salt and slow hashing right first

A pepper is an extra measure for the case where only the database is stolen. It adds the work of managing a secret somewhere else, and if you lose that secret you can no longer verify anyone's password.

So in practice, the first priority is using salt + a slow hash correctly via bcrypt/Argon2. Consider a pepper once you already have a key-management setup in place.

Sources (primary)

  • NIST, "SP 800-63B-4 Digital Identity Guidelines: Authentication and Authenticator Management" (August 2025) — pages.nist.gov (salt of at least 32 bits, storing salt and hash, a separately stored secret key)
  • RFC 9106, "Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications" — rfc-editor.org (16-byte salt recommended for password hashing)
  • OWASP, "Password Storage Cheat Sheet" — cheatsheetseries.owasp.org (salting, peppering, most libraries handle salts automatically)
  • PHC string format (the hash-string format used by Argon2 and others) — github.com/P-H-C
  • TechCrunch, "LinkedIn Confirms Hack And Leak Of 'Some' User Passwords" (June 6, 2012) — techcrunch.com (about 6.5 million, the company's statement on moving to hashing and salting)
  • Computerworld, "LinkedIn provides breach update -- sort of" (June 8, 2012) — computerworld.com (criticism of SHA-1-only hashing, passwords invalidated)

Classification

CWE classifies the types of weakness behind vulnerabilities; MITRE ATT&CK classifies attacker techniques. Both are maintained by MITRE and widely used to label vulnerability reports and detection rules.

CWE™: Copyright © 2006–2026, The MITRE Corporation. CWE is a trademark of The MITRE Corporation. The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. CWE Terms of Use

© 2026 The MITRE Corporation. This work is reproduced and distributed with the permission of The MITRE Corporation. MITRE ATT&CK and ATT&CK are registered trademarks of The MITRE Corporation. The MITRE Corporation (MITRE) hereby grants you a non-exclusive, royalty-free license to use ATT&CK® for research, development, and commercial purposes. Any copy you make for such purposes is authorized provided that you reproduce MITRE's copyright designation and this license in any such copy. ATT&CK Terms of Use

FAQ

QDoes a salt have to be kept secret?
A

No. A salt is not a 'secret key' — it's fine to store it next to the hash. Its purpose isn't secrecy; it's to make the same password store differently for every user, which defeats precomputation (rainbow tables) and bulk reuse cracking. The thing you keep secret is a different concept, a 'pepper' (see below).

QCan I reuse the same salt for all users?
A

No. The salt must be a random value that differs per user (ideally per password). A shared salt makes users with the same password store identical hashes, so an attacker can break many accounts with a single brute-force run. Generate a fresh one with a cryptographic RNG each time.

QDo I need to implement the salt myself?
A

Usually not. Purpose-built hashes like bcrypt, Argon2, and scrypt generate and store the salt for you (often embedded inside the hash string). Rather than adding a salt by hand, lean on these standard implementations — it's safer and more reliable.

QWhat is a rainbow table?
A

A table, computed in advance, that maps commonly used passwords to their hash values. A hash stored without a salt can be reversed just by looking it up in such a table. With a salt, the salt value isn't known when the table is built, so precomputed tables stop working.

QHow long should a salt be?
A

NIST SP 800-63B-4 requires at least 32 bits. The Argon2 specification (RFC 9106) recommends 16 bytes (128 bits) for password hashing. Standard bcrypt and Argon2 implementations generate a salt of adequate length automatically, so you rarely choose the length yourself.

QCan I use the username or user ID as the salt?
A

It's not recommended. Usernames and IDs are guessable and the same values (such as admin) appear on other services, which leaves room for tables built in advance for those values. The salt also wouldn't change when the password changes. Generate the salt with a cryptographic random number generator every time a password is set.