When AI Writes Your Auth Layer: Token Theft at Scale
APT28 is stealing auth tokens at scale by exploiting common misconfigurations. Learn why AI-generated authentication code is especially vulnerable and how to harden it.
State-Sponsored Attackers Are Harvesting Your Auth Tokens
Krebs on Security reported this week that hackers linked to Russia's APT28 (also known as Forest Blizzard) have been quietly harvesting authentication tokens from users across more than 18,000 networks. The campaign does not rely on malware. It exploits a single DNS setting in vulnerable routers to intercept and replay Microsoft Office authentication tokens.
The headline is about routers, but the deeper issue is token handling. The attackers succeed because authentication tokens are issued, stored, and transmitted in ways that make interception meaningful. That is an application-level problem, and it is one that AI-generated code handles poorly by default.
What AI Assistants Get Wrong About Token Security
When a developer asks an AI assistant to implement JWT authentication, the typical output looks something like this:
// Common AI-generated JWT implementation
const jwt = require('jsonwebtoken');
app.post('/login', (req, res) => {
const user = users.find(u => u.email === req.body.email);
const token = jwt.sign({ userId: user.id, email: user.email }, 'secret-key');
res.json({ token });
});
app.get('/profile', (req, res) => {
const token = req.headers.authorization;
const decoded = jwt.verify(token, 'secret-key');
res.json(decoded);
});
This code has several problems that make token theft more consequential:
1. The token has no expiry. A stolen token is valid forever.
2. The secret key is hardcoded and will likely end up in version control.
3. The authorization header is not parsed correctly. The Bearer prefix is included in the token string, causing silent failures that developers often patch by removing signature verification.
4. There is no token revocation mechanism. If a token is stolen, there is no way to invalidate it.
A hardened version addresses each of these:
// Hardened implementation
const jwt = require('jsonwebtoken');
const { randomUUID } = require('crypto');
const SECRET = process.env.JWT_SECRET; // Never hardcode
const TOKEN_EXPIRY = '15m'; // Short-lived tokens
app.post('/login', async (req, res) => {
const user = await verifyCredentials(req.body);
if (!user) return res.status(401).json({ error: 'Invalid credentials' });
const jti = randomUUID(); // Unique token ID for revocation
const token = jwt.sign(
{ sub: user.id, jti },
SECRET,
{ expiresIn: TOKEN_EXPIRY, algorithm: 'HS256' }
);
res.json({ token });
});
app.get('/profile', async (req, res) => {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) return res.status(401).end();
const token = authHeader.slice(7);
const decoded = jwt.verify(token, SECRET, { algorithms: ['HS256'] });
// Check revocation list
if (await isRevoked(decoded.jti)) return res.status(401).end();
res.json({ userId: decoded.sub });
});
The Refresh Token Problem
To avoid forcing users to log in every 15 minutes, developers add refresh tokens. AI assistants typically generate refresh token implementations that store tokens in localStorage:
// What AI generates, commonly
localStorage.setItem('refreshToken', token);
LocalStorage is accessible to any JavaScript running on the page. A single XSS vulnerability, including the kind that AI-generated code introduces through unsanitized template interpolation, gives an attacker access to every refresh token in storage. Refresh tokens belong in HttpOnly cookies:
// Correct refresh token storage
res.cookie('refreshToken', token, {
httpOnly: true, // Not accessible to JavaScript
secure: true, // HTTPS only
sameSite: 'strict', // No cross-site requests
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days in milliseconds
});
Why the APT28 Campaign Is a Warning for Vibe-Coded Apps
APT28's router campaign works because authentication tokens, once intercepted, can be replayed without the attacker needing credentials. This works best against tokens with long or no expiry, no binding to IP or device fingerprint, and no revocation infrastructure.
Those are precisely the characteristics of tokens issued by AI-generated authentication code. The threat model is not hypothetical. State-level adversaries are actively targeting authentication infrastructure, and the expansion of vibe-coded applications increases the surface area of vulnerable implementations.
Key Takeaways
- AI-generated JWT implementations typically lack expiry, use hardcoded secrets, and store refresh tokens in JavaScript-accessible storage, making them high-value targets for token theft campaigns.
- Short-lived access tokens (15 minutes) combined with HttpOnly cookie-stored refresh tokens and a revocation mechanism significantly reduce the window and impact of a token theft incident.
- Automated scanning that checks for missing
expiresIn fields, hardcoded secrets, and unsafe cookie attributes catches the most critical authentication misconfigurations before deployment.