Files
claude-skills/security-review/references/misconfiguration.md
2026-01-30 03:04:10 +00:00

436 lines
10 KiB
Markdown

# Security Misconfiguration Reference
## Overview
Security misconfiguration is one of the most common vulnerabilities. It occurs when security settings are not defined, implemented incorrectly, or left at insecure defaults. This includes missing security headers, overly permissive CORS, debug mode in production, and exposed sensitive endpoints.
---
## Security Headers
### Missing Headers
```python
# VULNERABLE: No security headers
@app.route('/')
def index():
return render_template('index.html')
# SAFE: Security headers configured
@app.after_request
def add_security_headers(response):
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY'
response.headers['X-XSS-Protection'] = '1; mode=block'
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
response.headers['Content-Security-Policy'] = "default-src 'self'"
response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
response.headers['Permissions-Policy'] = 'geolocation=(), microphone=()'
return response
```
### Header Checklist
| Header | Purpose | Secure Value |
|--------|---------|--------------|
| `X-Content-Type-Options` | Prevent MIME sniffing | `nosniff` |
| `X-Frame-Options` | Prevent clickjacking | `DENY` or `SAMEORIGIN` |
| `Strict-Transport-Security` | Force HTTPS | `max-age=31536000; includeSubDomains` |
| `Content-Security-Policy` | Prevent XSS, injection | Restrictive policy |
| `Referrer-Policy` | Control referrer leakage | `strict-origin-when-cross-origin` |
| `Permissions-Policy` | Disable browser features | Disable unused features |
### Content Security Policy
```python
# VULNERABLE: Overly permissive CSP
"Content-Security-Policy: default-src *"
"Content-Security-Policy: script-src 'unsafe-inline' 'unsafe-eval'"
# SAFE: Restrictive CSP
"Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'"
```
---
## CORS Misconfiguration
### Dangerous Patterns
```python
# VULNERABLE: Allow all origins
CORS(app, origins='*')
Access-Control-Allow-Origin: *
# VULNERABLE: Reflect origin without validation
@app.after_request
def add_cors(response):
response.headers['Access-Control-Allow-Origin'] = request.headers.get('Origin')
response.headers['Access-Control-Allow-Credentials'] = 'true'
return response
# VULNERABLE: Wildcard with credentials (browsers block, but shows misconfiguration)
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
# VULNERABLE: Null origin allowed
Access-Control-Allow-Origin: null
```
### Safe CORS Configuration
```python
# SAFE: Explicit allowlist
ALLOWED_ORIGINS = {
'https://app.example.com',
'https://admin.example.com'
}
@app.after_request
def add_cors(response):
origin = request.headers.get('Origin')
if origin in ALLOWED_ORIGINS:
response.headers['Access-Control-Allow-Origin'] = origin
response.headers['Access-Control-Allow-Credentials'] = 'true'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
return response
```
---
## Debug Mode in Production
### Dangerous Patterns
```python
# VULNERABLE: Debug mode enabled
# Flask
app.run(debug=True)
DEBUG = True
# Django
DEBUG = True # in settings.py
# Express
app.set('env', 'development')
# Spring Boot
spring.devtools.restart.enabled=true
management.endpoints.web.exposure.include=*
```
### Detection
```python
# Check for debug indicators
if app.debug:
# Exposes stack traces, allows code execution in some frameworks
pass
# Check environment variables
if os.environ.get('DEBUG') == 'true':
pass
if os.environ.get('FLASK_ENV') == 'development':
pass
```
---
## Default Credentials
### Patterns to Flag
```python
# VULNERABLE: Default/weak credentials
username = 'admin'
password = 'admin'
password = 'password'
password = '123456'
password = 'changeme'
password = 'default'
# VULNERABLE: Well-known default credentials
# Database defaults
DB_PASSWORD = 'root'
DB_PASSWORD = 'postgres'
DB_PASSWORD = 'mysql'
# Admin panel defaults
ADMIN_PASSWORD = 'admin123'
SECRET_KEY = 'development-secret-key'
```
### Configuration Files to Check
```yaml
# Docker Compose
services:
db:
environment:
MYSQL_ROOT_PASSWORD: root # VULNERABLE
POSTGRES_PASSWORD: postgres # VULNERABLE
# Kubernetes Secrets (base64 encoded defaults)
apiVersion: v1
kind: Secret
data:
password: YWRtaW4= # 'admin' base64 encoded - VULNERABLE
```
---
## Exposed Endpoints
### Admin/Debug Endpoints
```python
# VULNERABLE: Exposed debug endpoints
@app.route('/debug')
@app.route('/admin') # without authentication
@app.route('/metrics') # without authentication
@app.route('/health') # may expose sensitive info
@app.route('/env')
@app.route('/config')
@app.route('/phpinfo.php')
@app.route('/.git')
@app.route('/.env')
# Spring Boot Actuator endpoints
/actuator/env
/actuator/heapdump
/actuator/configprops
/actuator/mappings
```
### Protection
```python
# SAFE: Protect sensitive endpoints
@app.route('/admin')
@require_admin
def admin_panel():
pass
@app.route('/metrics')
@require_internal_network
def metrics():
pass
# Spring Boot: Restrict actuator
management.endpoints.web.exposure.include=health,info
management.endpoint.health.show-details=never
```
---
## TLS/SSL Misconfiguration
### Insecure Patterns
```python
# VULNERABLE: SSL verification disabled
requests.get(url, verify=False)
urllib3.disable_warnings()
# VULNERABLE: Weak TLS versions
ssl_context.minimum_version = ssl.TLSVersion.TLSv1 # Use TLS 1.2+
# VULNERABLE: Weak cipher suites
ssl_context.set_ciphers('ALL')
ssl_context.set_ciphers('DEFAULT')
```
### Secure Configuration
```python
# SAFE: Proper TLS configuration
import ssl
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.minimum_version = ssl.TLSVersion.TLSv1_2
context.set_ciphers('ECDHE+AESGCM:DHE+AESGCM:ECDHE+CHACHA20')
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
```
---
## Directory Listing
### Dangerous Patterns
```nginx
# VULNERABLE: Directory listing enabled
# Nginx
autoindex on;
# Apache
Options +Indexes
# Python
python -m http.server # Lists directories by default
```
### Secure Configuration
```nginx
# SAFE: Directory listing disabled
# Nginx
autoindex off;
# Apache
Options -Indexes
```
---
## Verbose Error Messages
### Dangerous Patterns
```python
# VULNERABLE: Detailed errors in response
@app.errorhandler(Exception)
def handle_error(e):
return jsonify({
'error': str(e),
'traceback': traceback.format_exc(),
'query': last_executed_query,
'config': app.config
}), 500
# VULNERABLE: Stack traces exposed
app.config['PROPAGATE_EXCEPTIONS'] = True
```
### Secure Error Handling
```python
# SAFE: Generic error messages
@app.errorhandler(Exception)
def handle_error(e):
app.logger.error(f"Error: {e}", exc_info=True) # Log details server-side
return jsonify({'error': 'An unexpected error occurred'}), 500
```
---
## Cookie Security
### Insecure Patterns
```python
# VULNERABLE: Insecure cookie settings
response.set_cookie('session', value) # Missing flags
# VULNERABLE: Explicit insecure flags
response.set_cookie('session', value, secure=False, httponly=False, samesite='None')
```
### Secure Cookie Configuration
```python
# SAFE: Secure cookie settings
response.set_cookie(
'session',
value,
secure=True, # HTTPS only
httponly=True, # No JavaScript access
samesite='Lax', # CSRF protection
max_age=3600, # Reasonable expiration
path='/',
domain='.example.com'
)
# Flask session configuration
app.config['SESSION_COOKIE_SECURE'] = True
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
```
---
## Permissive File Permissions
### Dangerous Patterns
```python
# VULNERABLE: World-readable sensitive files
os.chmod(config_file, 0o777)
os.chmod(private_key, 0o644)
# VULNERABLE: Overly permissive umask
os.umask(0o000)
```
### Secure Permissions
```python
# SAFE: Restrictive permissions
os.chmod(config_file, 0o600) # Owner read/write only
os.chmod(private_key, 0o400) # Owner read only
os.chmod(script, 0o700) # Owner execute only
```
---
## HTTP Methods
### Dangerous Patterns
```python
# VULNERABLE: All methods allowed
@app.route('/api/data', methods=['GET', 'POST', 'PUT', 'DELETE', 'TRACE', 'OPTIONS'])
# VULNERABLE: TRACE method enabled (XST attacks)
# VULNERABLE: Unnecessary methods on sensitive endpoints
```
### Secure Configuration
```python
# SAFE: Explicit method restrictions
@app.route('/api/data', methods=['GET'])
def get_data():
pass
@app.route('/api/data', methods=['POST'])
@require_auth
def create_data():
pass
```
---
## Grep Patterns for Detection
```bash
# Debug mode
grep -rn "debug.*=.*[Tt]rue\|DEBUG.*=.*[Tt]rue" --include="*.py" --include="*.js" --include="*.json"
# CORS wildcards
grep -rn "Access-Control-Allow-Origin.*\*\|origins.*\*\|origin.*\*" --include="*.py" --include="*.js"
# SSL verification disabled
grep -rn "verify.*=.*[Ff]alse\|rejectUnauthorized.*false\|NODE_TLS_REJECT_UNAUTHORIZED" --include="*.py" --include="*.js"
# Default credentials
grep -rn "password.*=.*['\"]admin\|password.*=.*['\"]root\|password.*=.*['\"]123456" --include="*.py" --include="*.yaml" --include="*.yml"
# Missing security headers (check for absence)
grep -rn "after_request\|middleware" --include="*.py" | grep -v "X-Content-Type-Options\|X-Frame-Options"
# Exposed endpoints
grep -rn "@app.route.*debug\|@app.route.*admin\|@app.route.*config\|/actuator" --include="*.py" --include="*.java"
```
---
## References
- [OWASP Security Misconfiguration](https://owasp.org/Top10/A05_2021-Security_Misconfiguration/)
- [OWASP HTTP Security Headers](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html)
- [OWASP TLS Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html)
- [CWE-16: Configuration](https://cwe.mitre.org/data/definitions/16.html)