Security fix patterns for authentication and authorization vulnerabilities (credentials, JWT, deserialization, access control). Provides language-specific secure implementations.
Provides secure code patterns to fix authentication and authorization vulnerabilities like hardcoded credentials, weak JWTs, unsafe deserialization, and missing access controls. Use after finding auth vulnerabilities to replace insecure implementations with language-specific secure alternatives.
/plugin marketplace add Zate/cc-plugins/plugin install security@cc-pluginsThis 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