The JWT Secret AI Tools Love to Hardcode as 'secret'
AI coding tools often sign login tokens with a placeholder string like 'secret' or 'mysecret', and that placeholder ships straight to production. Anyone who finds it can forge a token for any user.

Your login tokens are signed with the word "secret". Anyone who guesses that can log in as any user on your site, including the admin.
This happens because AI coding tools write JWT auth fast, and they need a signing key to make the demo work. They drop in a placeholder like secret or mysecret so the code runs right away. You test it, it works, you ship it. Nobody goes back to swap the placeholder for a real key, because nothing in the app tells you it's still there.
The scary part is how easy this is to find. JWT secrets get brute-forced with public wordlists built from exactly this kind of default. If your secret is short or common, a tool like hashcat can crack it in seconds. Once someone has your secret, they can mint a token for user ID 1, or for role: admin, and your server will accept it as real.
Here's what the broken version looks like:
const jwt = require('jsonwebtoken');
function signToken(user) {
return jwt.sign({ id: user.id, role: user.role }, 'secret', {
expiresIn: '7d',
});
}That string, 'secret', is sitting right there in your source code. If your repo is public, or ever was, it's already out. Even in a private repo, it's the first thing a wordlist attack will try.
Here's the fix. Generate a long random key, keep it out of your code, and load it from the environment:
const jwt = require('jsonwebtoken');
function signToken(user) {
return jwt.sign({ id: user.id, role: user.role }, process.env.JWT_SECRET, {
expiresIn: '7d',
});
}Generate the actual value with something like openssl rand -hex 64, and put it in your .env file, not your code. Add .env to .gitignore if it isn't already there. Set the same variable in your hosting provider's dashboard for production.
One more thing worth checking: does your code crash or fall back to a default if JWT_SECRET is missing? A silent fallback to undefined or 'secret' defeats the whole fix. Make the app refuse to start without a real secret set.
To check your own app, search your codebase for jwt.sign and jwt.verify. Look at the second argument in each call. If you see a short string in quotes instead of an environment variable, that's your signing key sitting in plain text. Then check your git history too, since an old commit might still have a secret you rotated out of the current code.
If you want someone else to check this for you, get a free assessment. We'll scan your app's auth code and tell you what's exposed, within 24 hours.
VibeAudits audits apps built with Cursor, Lovable, Bolt, Claude Code, Replit, and other AI tools.