Security fix patterns for authentication and authorization vulnerabilities (credentials, JWT, deserialization, access control). Provides language-specific secure implementations.
This skill inherits all available tools. When active, it can use any tool Claude has access to.
Actionable fix patterns for auth-related security vulnerabilities.
Credentials in source code are exposed in version control and can be extracted from compiled code.
Don't:
# VULNERABLE: Hardcoded credentials
API_KEY = "sk-1234567890abcdef"
DB_PASSWORD = "admin123"
JWT_SECRET = "mysupersecretkey"
Do:
# SECURE: Environment variables
import os
API_KEY = os.environ.get('API_KEY')
DB_PASSWORD = os.environ.get('DB_PASSWORD')
# SECURE: Configuration file (not in git)
import configparser
config = configparser.ConfigParser()
config.read('/etc/myapp/secrets.ini')
api_key = config['api']['key']
# SECURE: Secret manager (AWS Secrets Manager)
import boto3
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId='myapp/api-key')
api_key = response['SecretString']
# SECURE: Vault
import hvac
client = hvac.Client(url='https://vault.example.com')
secret = client.secrets.kv.read_secret_version(path='myapp/api-key')
api_key = secret['data']['data']['value']
Don't:
# VULNERABLE: .env committed to git
DATABASE_URL=postgres://admin:password123@localhost/db
API_SECRET=sk-live-abcdef123456
# VULNERABLE: docker-compose.yml with secrets
environment:
- DB_PASSWORD=admin123
Do:
# SECURE: .env.example (template, no real values)
DATABASE_URL=postgres://user:password@host/database
API_SECRET=your-api-secret-here
# SECURE: docker-compose with external secrets
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
secrets:
db_password:
external: true
# SECURE: Use secret references
environment:
- DB_PASSWORD=${DB_PASSWORD} # Set at runtime
ASVS: V13.3.1, V13.3.2 References: OWASP Secrets Management
Deserializing untrusted data can lead to remote code execution.
Don't:
# VULNERABLE: pickle with untrusted data
import pickle
data = pickle.loads(user_input)
# VULNERABLE: yaml.load without SafeLoader
import yaml
data = yaml.load(user_input, Loader=yaml.Loader)
Do:
# SECURE: JSON for untrusted data
import json
data = json.loads(user_input)
# SECURE: yaml.safe_load
import yaml
data = yaml.safe_load(user_input)
# SECURE: If pickle is required, use hmac signing
import pickle
import hmac
import hashlib
def secure_loads(data, key):
signature, payload = data[:64], data[64:]
expected = hmac.new(key, payload, hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature, expected):
raise ValueError("Invalid signature")
return pickle.loads(payload)
Don't:
// VULNERABLE: ObjectInputStream with untrusted data
ObjectInputStream ois = new ObjectInputStream(inputStream);
Object obj = ois.readObject();
Do:
// SECURE: Use JSON instead
ObjectMapper mapper = new ObjectMapper();
MyClass obj = mapper.readValue(jsonString, MyClass.class);
// SECURE: If Java serialization required, use allowlist
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"com.myapp.*;java.util.*;!*"
);
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(filter);
Don't:
// VULNERABLE: unserialize with user input
$data = unserialize($_POST['data']);
Do:
// SECURE: JSON instead
$data = json_decode($_POST['data'], true);
// SECURE: If unserialize required, use allowed_classes
$data = unserialize($input, ['allowed_classes' => ['AllowedClass']]);
ASVS: V1.5.1, V1.5.2 References: OWASP Deserialization
Weak JWT configuration allows token forgery or manipulation.
Don't:
// VULNERABLE: "none" algorithm accepted
const decoded = jwt.verify(token, secret); // May accept alg: "none"
// VULNERABLE: Weak secret
const token = jwt.sign(payload, 'secret');
// VULNERABLE: HS256 with RSA public key
const decoded = jwt.verify(token, publicKey); // Algorithm confusion
Do:
// SECURE: Explicit algorithm specification
const jwt = require('jsonwebtoken');
// Signing
const token = jwt.sign(payload, privateKey, {
algorithm: 'RS256',
expiresIn: '1h',
issuer: 'myapp',
audience: 'myapp-users'
});
// Verification with explicit options
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'], // Explicitly allow only RS256
issuer: 'myapp',
audience: 'myapp-users'
});
// SECURE: Strong symmetric key (if using HS256)
const crypto = require('crypto');
const secret = crypto.randomBytes(64).toString('hex'); // 512 bits
Do:
import jwt
# Signing
token = jwt.encode(
payload,
private_key,
algorithm='RS256',
headers={'kid': key_id}
)
# Verification
decoded = jwt.decode(
token,
public_key,
algorithms=['RS256'], # Explicit allowlist
audience='myapp-users',
issuer='myapp'
)
ASVS: V9.2.1, V9.2.2, V9.3.1 References: OWASP JWT Cheat Sheet
Endpoints accessible without proper authorization checks allow unauthorized access.
Don't:
# VULNERABLE: No authorization check
@app.route('/api/users/<int:user_id>')
def get_user(user_id):
return User.query.get_or_404(user_id)
# VULNERABLE: Client-side only check
@app.route('/admin/dashboard')
def admin_dashboard():
# Relies on frontend to hide link
return render_template('admin.html')
Do:
# SECURE: Authorization decorator
from functools import wraps
from flask import g, abort
def require_permission(permission):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not g.user.has_permission(permission):
abort(403)
return f(*args, **kwargs)
return decorated_function
return decorator
@app.route('/api/users/<int:user_id>')
@require_permission('users:read')
def get_user(user_id):
# Also check ownership for user's own data
if g.user.id != user_id and not g.user.is_admin:
abort(403)
return User.query.get_or_404(user_id)
Do:
// SECURE: Middleware for authorization
const authorize = (requiredRole) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
if (!req.user.roles.includes(requiredRole)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
};
// SECURE: Resource ownership check
app.get('/api/users/:id', authorize('user'), (req, res) => {
if (req.params.id !== req.user.id && !req.user.roles.includes('admin')) {
return res.status(403).json({ error: 'Forbidden' });
}
// Return user data
});
Do:
// SECURE: Method-level security
@PreAuthorize("hasRole('ADMIN') or #userId == authentication.principal.id")
@GetMapping("/users/{userId}")
public User getUser(@PathVariable Long userId) {
return userService.findById(userId);
}
// SECURE: Custom authorization
@GetMapping("/resources/{id}")
public Resource getResource(@PathVariable Long id, Authentication auth) {
Resource resource = resourceService.findById(id);
if (!resource.getOwnerId().equals(auth.getName()) &&
!auth.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMIN"))) {
throw new AccessDeniedException("Not authorized");
}
return resource;
}
ASVS: V8.2.1, V8.2.2, V8.2.3 References: OWASP Access Control
| Vulnerability | Fix Pattern | Key Libraries |
|---|---|---|
| Hardcoded secrets | Environment variables, secret managers | dotenv, boto3, hvac |
| Unsafe deserialization | JSON, safe loaders | json, yaml.safe_load |
| Weak JWT | Explicit algorithms, strong keys | jsonwebtoken, PyJWT |
| Missing authz | Middleware, decorators | Flask-Login, Passport.js |
remediation-injection - Injection fixesremediation-crypto - Cryptography fixesremediation-config - Configuration fixesvulnerability-patterns - Detection patterns