It's a known risk rather than an outright mistake. Anything in localStorage can be read by any JavaScript running on your page, so if an attacker ever gets a script onto your site, through a compromised package or an injection bug, they can copy your users' tokens and log in as them from anywhere. OWASP recommends against keeping sensitive data there. A cookie marked HttpOnly can't be read by scripts at all, which is why it's the usual safer choice, paired with protection against cross-site request forgery.
What's the problem
Your app logs users in and stores a token (often a JWT) in the browser's localStorage, then sends it with each request. It works. Someone, a security scanner or an article, says that's insecure, and you need to know whether to change it before launch.
Why it happens
- localStorage is easy. It's the simplest way for a frontend to keep a token, and many tutorials use it.
- Every script on the page can read it. That includes every third-party package your app ships and any script an attacker manages to inject. One cross-site scripting bug turns into stolen sessions.
- Stolen tokens keep working. A JWT is usually valid until it expires, wherever it's used from. Long expiry times make a theft worse.
- The token is only part of it. Weak signing secrets, tokens that never expire, and servers that don't check the signature properly are common JWT problems too.
How to fix it
- Move the session to an
HttpOnly,Securecookie set by your server, withSameSiteset, so scripts can't read it and it only travels over HTTPS. - Add protection against cross-site request forgery if your cookies are sent cross-site, since browsers attach cookies automatically.
- Keep tokens short-lived, and use a refresh mechanism, so a stolen one stops working quickly.
- Check the server side: a long random signing secret, signatures verified on every request, and expiry enforced.
- Reduce the chance of injected scripts: escape user input when displaying it, keep packages updated, and add a Content Security Policy.
- If moving to cookies is too big a change right now, at least shorten token lifetimes and fix any injection bugs first. That's the attack that makes localStorage dangerous.
When to call Preventionlabs
If your login is a standard library used the standard way, these changes are well documented. Call us when authentication was hand-built, half the app depends on reading the token, or you're not sure what else is wrong with it. Authentication is on the MVP-level protection checklist in every resurrection, tested the way an attacker would test it, then fixed.
Submit your project for a free assessmentFree assessment. $10,000 AUD flat to get it live, only if we take it on and you go ahead.
Sources
- OWASP: HTML5 Security Cheat Sheet: Local Storagesecurity standards body
Therefore, it's recommended to avoid storing any sensitive information in local storage where authentication would be assumed.
- MDN Web Docs: Set-Cookie: HttpOnlyweb reference
Forbids JavaScript from accessing the cookie, for example, through the Document.cookie property.
- OWASP: OWASP Top 10:2025security standards body
A07:2025 - Authentication Failures