CWE-640 in APIs
- CWE ID
- CWE-640
- Category
- Authentication
- Severity
- HIGH
- Short Name
- Weak Recovery
What is CWE-640?
CWE-640 is officially titled Weak Password Recovery Mechanism for Forgotten Password. According to MITRE's Common Weakness Enumeration, this weakness occurs when a password recovery mechanism is implemented in a way that allows an attacker to gain unauthorized access to user accounts. The core problem is that the recovery process itself becomes an attack vector, often due to insufficient verification of the account owner's identity.
The weakness typically manifests when systems rely on easily guessable or publicly available information for account recovery. Common examples include security questions with answers that can be found on social media, predictable reset tokens, or email-based recovery without proper verification. An attacker who successfully exploits this weakness gains the same access as the legitimate user, including the ability to change passwords, view sensitive data, or perform privileged operations.
CWE-640 in API Contexts
In API environments, CWE-640 takes on specific characteristics that make it particularly dangerous. APIs often handle password recovery through automated endpoints that lack the human verification steps present in web interfaces. This creates several unique attack surfaces:
- Token-based recovery endpoints that accept predictable or brute-forceable tokens
- Information disclosure through error messages that reveal whether an account exists
- Timing attacks where response times leak information about account validity
- Lack of rate limiting on recovery endpoints allowing enumeration attacks
API password recovery mechanisms frequently suffer from predictable token generation. Many systems use timestamp-based tokens, sequential identifiers, or weak random number generators that attackers can brute force. The /reset-password or /forgot-password endpoints often return different responses for valid vs invalid accounts, enabling username enumeration. Additionally, APIs may lack the CAPTCHAs or rate limiting that web applications typically employ, making automated attacks more feasible.
The distributed nature of API clients compounds the problem. Unlike web applications where you control the client-side implementation, API clients can be custom-built tools that automate recovery attempts at scale. This makes weak recovery mechanisms exponentially more dangerous in API contexts compared to traditional web applications.
Detection
Detecting CWE-640 in APIs requires examining both the recovery mechanism implementation and its security controls. Here are the key detection methods:
Manual Testing involves attempting password recovery with various accounts, including non-existent ones, to observe response patterns. Look for differences in response times, error messages, or HTTP status codes that could enable account enumeration. Test token predictability by requesting multiple recovery tokens and analyzing their structure for patterns or sequential elements.
Automated Scanning with tools like middleBrick can identify CWE-640 vulnerabilities by testing recovery endpoints systematically. middleBrick's black-box scanning approach sends requests to /forgot-password and /reset-password endpoints without requiring credentials. The scanner checks for:
- Information disclosure through error messages
- Weak token generation patterns
- Missing rate limiting on recovery endpoints
- Predictable reset URLs or tokens
- Insufficient verification steps in the recovery flow
Code Review should focus on the token generation algorithm, verification logic, and rate limiting implementation. Look for use of insecure random number generators, lack of expiration on recovery tokens, or verification that relies on easily obtainable information.
middleBrick's API Security Scanner specifically tests for CWE-640 by analyzing the password recovery flow. The scanner attempts recovery with both valid and invalid accounts to detect information leakage, tests token predictability, and verifies that rate limiting is properly implemented. For API developers, middleBrick provides a quick way to identify this weakness without setting up complex testing environments. Simply run middlebrick scan https://yourapi.com and the scanner will automatically test recovery endpoints and report any weaknesses found.
Remediation
Fixing CWE-640 requires implementing strong verification mechanisms and secure token handling. Here are code-level solutions:
Secure Token Generation is fundamental. Replace predictable tokens with cryptographically secure random values:
// Insecure - predictable timestamp-based token
const insecureToken = Date.now() + userId;// Secure - cryptographically random token
import crypto from 'crypto';
const secureToken = crypto.randomBytes(32).toString('hex');
const tokenHash = crypto.createHash('sha256').update(secureToken).digest('hex');
// Store tokenHash in database, send secureToken to user
Rate Limiting and Account Enumeration Prevention ensures attackers cannot brute force recovery attempts:
const MAX_RECOVERY_ATTEMPTS = 5;
const RECOVERY_WINDOW = 15 * 60 * 1000; // 15 minutes
app.post('/api/forgot-password', rateLimit({ windowMs: RECOVERY_WINDOW, max: MAX_RECOVERY_ATTEMPTS }), async (req, res) => {
const { email } = req.body;
// Always return same response regardless of account existence
const success = await processRecoveryRequest(email);
res.json({
message: success ? 'If account exists, recovery instructions sent' : 'If account exists, recovery instructions sent'
});
});
Multi-Factor Verification adds additional security layers beyond just email access:
async function verifyRecovery(token, userId) {
const recoveryRecord = await RecoveryToken.findOne({
where: { tokenHash, userId, expiresAt: { [Op.gt]: new Date() } }
});
if (!recoveryRecord) {
return false;
}
// Require additional verification beyond token
const isVerified = await verifySecurityQuestions(userId, req.body.answers) ||
await sendOTPToRegisteredPhone(userId);
if (isVerified) {
await recoveryRecord.destroy(); // Invalidate token after use
return true;
}
return false;
}
Time-Limited Tokens with Single Use prevents token reuse attacks:
const RECOVERY_TOKEN_EXPIRY = 1 * 60 * 60 * 1000; // 1 hour
async function createRecoveryToken(userId) {
const token = crypto.randomBytes(32).toString('hex');
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
await RecoveryToken.create({
userId,
tokenHash,
expiresAt: new Date(Date.now() + RECOVERY_TOKEN_EXPIRY),
used: false
});
return token;
}
Audit Logging helps detect and respond to suspicious recovery attempts:
async function logRecoveryAttempt(email, ipAddress, success) {
await RecoveryAttempt.create({
email,
ipAddress,
success,
userAgent: req.get('User-Agent')
});
// Alert on suspicious patterns
const recentAttempts = await RecoveryAttempt.count({
where: {
ipAddress,
createdAt: { [Op.gt]: new Date(Date.now() - 24 * 60 * 60 * 1000) }
}
});
if (recentAttempts > 100) {
await alertSecurityTeam({
message: 'High volume of recovery attempts from single IP',
details: { ipAddress, count: recentAttempts }
});
}
}