Does a password salt need to be kept secret?
Short answer
No. A salt is a unique, random value stored right alongside the hash; its job is to make identical passwords hash differently and to defeat precomputed rainbow tables — not to stay secret. It's fine if an attacker who steals the database also gets the salts. What actually protects passwords is a slow, salted hash (bcrypt, scrypt, Argon2). A separate, optional secret 'pepper' is a different concept.
Candidates often assume a salt is a kind of secret key that must be hidden. It isn't, and treating it like one reveals a misunderstanding of what salting actually does.
What a salt is for
A salt is a unique, random value generated per password and stored in plaintext right next to the resulting hash. Its only purpose is to ensure that two users with the same password produce different hashes, and to make precomputed attacks — rainbow tables — useless. A rainbow table is built ahead of time against unsalted hashes; if every password has its own random salt, the attacker would need a separate table per salt, which destroys the economics of precomputation.
Why secrecy isn't the point
Because the salt lives beside the hash, an attacker who steals your database gets the salts too. That's expected and fine. The salt doesn't make a single guess any harder to verify — it makes bulk attacks across many accounts impractical, since each candidate password must be re-hashed against each user's salt rather than looked up once. Secrecy was never the mechanism.
What actually protects passwords
Real protection comes from a slow, salted, adaptive hash: bcrypt, scrypt, or Argon2 (Argon2id is the modern recommendation). These deliberately burn CPU and memory so each guess is expensive, slowing offline cracking to a crawl. A fast general-purpose hash like SHA-256, even salted, can be tried billions of times per second on a GPU.
The pepper: a different concept
There is a secret in this space — the pepper — but it's distinct from a salt. A pepper is a single site-wide secret value mixed in before or after hashing, stored outside the database (e.g. in an HSM or app config). Because it isn't in the stolen database dump, it adds protection precisely when the database leaks. Confusing salt with pepper is the heart of this gotcha: the salt is public per-record randomness; the pepper is a hidden global secret.
Likely follow-ups
- What is a pepper and how does it differ from a salt?
- Why does a unique salt per user defeat precomputed rainbow tables?
- Why isn't a fast hash like SHA-256 enough for storing passwords?