Security Misconfiguration
Theory
Security Misconfiguration rose from #5 in 2021 to #2 in 2025: 100% of applications tested were found to have some form of misconfiguration, across more than 719,000 recorded occurrences. The 2025 edition attributes the jump to the shift toward highly configurable software, where every knob is a chance to get it wrong. It encompasses every case where a system is set up insecurely: wrong defaults left in place, unnecessary features enabled, overly permissive permissions, or missing security headers. The defining characteristic: the vulnerability is in how the software is deployed or configured, not in the code itself.
Types of Security Misconfiguration
- Debug endpoints in production —
/debug,/_debug/toolbar,/actuator/envendpoints that expose env vars, secrets, and stack traces - Default credentials — admin:admin, admin:password on databases (MySQL root with no password), admin panels (Jenkins, Tomcat, Elasticsearch)
- Verbose error messages — full stack traces returned to the browser leak framework versions, file paths, database structure, and internal logic
- Open cloud storage — S3 buckets, Azure Blob storage, or GCS buckets with public read access containing sensitive files
- Missing security headers — no Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, or Strict-Transport-Security
- Unnecessary services exposed — Redis, MongoDB, Memcached, or Elasticsearch directly accessible from the internet with no authentication
- XML External Entity (XXE) enabled — XML parsers configured to resolve external entities by default
Debug Endpoint — Vulnerable Code
# VULNERABLE — debug route left in production with no auth guard
@app.get("/debug")
def debug_info():
return {
"env": dict(os.environ), # leaks SECRET_KEY, DB_PASSWORD, API_KEYS...
"config": app.state.config, # internal config values
"database_url": settings.DB_URL, # full connection string with credentials
}
# This is what Spring Boot Actuator exposes by default:
# GET /actuator/env → all environment variables
# GET /actuator/heapdump → full JVM heap dump (extract credentials from memory)
# GET /actuator/mappings → all route mappings (attack surface map)
Fixed Code
# FIXED — debug endpoint only exists in non-production environments
import os
if os.getenv("ENVIRONMENT") != "production":
@app.get("/debug")
def debug_info():
# Even in dev, never expose raw env vars
return {"status": "debug mode", "version": app.version}
# For frameworks with built-in debug features:
# Flask: app.run(debug=False) in production
# Django: DEBUG = False in settings.py for production
# Spring: management.endpoints.web.exposure.exclude=* in application.properties
Missing Security Headers — Vulnerable vs Fixed
# VULNERABLE — no security headers; browser has no protection hints
# Response headers:
Content-Type: text/html
# FIXED — add security headers middleware
from fastapi.middleware import Middleware
@app.middleware("http")
async def add_security_headers(request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
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=(), camera=()"
return response
Real-World Breaches
- Capital One (2019) — An EC2 instance had an overly permissive IAM role + SSRF vulnerability. The misconfigured role allowed reading 100M customer records from S3. $80M fine.
- Elasticsearch incidents (ongoing) — Thousands of databases left internet-facing with no authentication. Multiple breaches of millions of records each year
- GrayShift (2018) — An internal web panel had no password protection; source code and pricing leaked
- Microsoft Power Apps (2021) — Default portal configuration made data public; 38 million records (COVID vaccination status, SSNs) were exposed across 47 organisations
How to Fix — Checklist
- Harden defaults — disable everything you don't need; enable only what you do. Run
CIS Benchmarkhardening guides for your OS, DB, and cloud provider - Change all default credentials — automate this in your provisioning scripts (Terraform, Ansible). Fail CI if default creds are detected
- Remove debug features from production builds — use build flags or environment checks; never ship
debug=Trueto prod - Security headers — use securityheaders.com to audit and implement all recommended headers
- Scan with tools —
OWASP ZAP,Nuclei,AWS Config,Scout Suitefor cloud; integrate into CI/CD pipeline - Principle of least privilege — every service, container, and cloud role should have only the permissions it needs and nothing more
Debug Endpoint Exposes Sensitive Data
A debug endpoint was left enabled in production and exposes environment variables, config values, and secrets.
/web/a02/debug directly.Default Credentials
The management panel uses default credentials that were never changed.
admin, password admin.