Back to Cheat Sheets

⚙️ Security MisconfigurationAPI 2019

OWASP API Security Top 10 2019 - API7

HIGH RISK

📋 What Is It?

Security Misconfiguration is the category for everything that is insecure because of how the API and its infrastructure are set up, rather than how the business logic is written. Insecure defaults left in place, debug modes shipped to production, permissive CORS, missing TLS or security headers, verbose errors, open cloud storage, unnecessary HTTP methods, and unpatched components all live here.

It is the broadest and most common category because it spans every layer - application framework, web server, container, orchestrator, cloud account - and because a configuration that was safe last quarter drifts silently as environments change.

API7 OWASP Rank 2019
Every Layer Of The Stack
Automated Discovery

⚠️ Common Exploits

  • Debug Mode in Production: stack traces, config dumps, interactive consoles
  • Permissive CORS: Access-Control-Allow-Origin: * with credentials
  • Default Credentials: shipped admin accounts on consoles and databases
  • Verbose Errors: SQL text, file paths, framework and version banners
  • Missing TLS / Weak Ciphers: cleartext endpoints, no HSTS
  • Unnecessary Methods: TRACE, PUT, OPTIONS left enabled
  • Exposed Infrastructure: open buckets, unauthenticated dashboards, metrics endpoints
  • Unpatched Components: known-vulnerable framework or server versions

🔴 Attack Flow

1. Fingerprint the stack from headers, error pages, and banners
↓
2. Probe for debug endpoints, docs, metrics, and admin consoles
↓
3. Test CORS, TLS, methods, and default credentials
↓
4. Trigger errors deliberately and read what leaks
↓
5. IMPACT: Config disclosure, data access, or a foothold - no exploit code needed!

❌ Vulnerable Code

# Bad: debug shipped to production app.run(host='0.0.0.0', debug=True) ← traceback console = remote code execution DEBUG = True ALLOWED_HOSTS = ['*'] // Bad: CORS wide open, with credentials app.use(cors({ origin: '*', credentials: true })); ← any site reads authenticated responses // Bad: raw error handed to the client } catch (err) { res.status(500).json({ error: err.stack }); ← paths, queries, versions } # Bad: cleartext, default creds, everything exposed services: api: ports: ['80:8080'] # no TLS db: environment: POSTGRES_PASSWORD: postgres ← default credential ports: ['5432:5432'] ← database on the public internet

✅ Secure Code

# Good: production defaults, driven by config not by hope DEBUG = os.environ.get('DEBUG', 'false').lower() == 'true' # false unless set ALLOWED_HOSTS = os.environ['ALLOWED_HOSTS'].split(',') # explicit, required // Good: an explicit origin allow-list app.use(cors({ origin: ['https://app.example.com'], credentials: true, methods: ['GET', 'POST'], })); // Good: log the detail, return a reference } catch (err) { logger.error({ err, requestId: req.id }); res.status(500).json({ error: 'Internal error', requestId: req.id }); } // Good: security headers and transport hardening app.use(helmet({ hsts: { maxAge: 31536000, includeSubDomains: true } })); app.disable('x-powered-by'); # Good: least-privilege runtime, secrets from a manager, no default creds services: api: read_only: true user: "10001:10001" cap_drop: [ALL] environment: DB_PASSWORD_FILE: /run/secrets/db_password

✓ Prevention Checklist

  • Harden by default; make production the safe path, not the exception
  • Disable debug modes, consoles, and directory listings in production
  • Return generic errors with a correlation id; log detail server-side
  • Configure CORS with an explicit origin allow-list
  • Enforce TLS everywhere, with HSTS and modern cipher suites
  • Set security headers and remove version banners
  • Allow only the HTTP methods each route needs
  • Replace every default credential; store secrets in a manager
  • Keep infrastructure as code and scan it in CI
  • Patch frameworks, servers, and images on a schedule
  • Re-scan configuration continuously - drift is the norm

🔍 Detection & Tools

Scanning:

nmap testssl.sh Nikto OWASP ZAP Trivy

Config & Cloud:

Checkov tfsec Prowler / ScoutSuite CIS Benchmarks

How to Test:

  • Request a bad route and read the error body and headers
  • Send an Origin header from an unrelated site and inspect CORS response
  • Enumerate /debug, /actuator, /metrics, /swagger, /.env
  • Run a TLS scan; check HSTS and cipher suites
  • Try OPTIONS/TRACE and unexpected methods
  • Attempt documented default credentials on every console

🌍 Real-World

These are documented incident classes - recurring patterns rather than single CVEs.

  • Debug consoles exposed: a framework's interactive traceback page reachable in production turns any error into arbitrary code execution.
  • Wildcard CORS with credentials: any origin can read authenticated API responses from a victim's browser.
  • Open storage and dashboards: unauthenticated buckets, search clusters, and metrics endpoints found by internet-wide scanners within hours of exposure.
  • Default credentials: shipped admin accounts on message queues, databases, and admin panels used directly by automated bots.
  • Verbose errors: SQL statements and file paths in responses hand an attacker the map for the next stage.

📌 Quick Tips

  • DO NOT ship debug mode or raw stack traces
  • DO NOT combine origin: * with credentials
  • DO NOT leave default credentials anywhere
  • DO codify configuration and scan it in CI
  • DO enforce TLS, HSTS, and security headers
  • DO re-check for drift on a schedule

📜 Compliance

Related Standards:

  • OWASP API Security Top 10 2019 - API7
  • Maps to API8:2023 Security Misconfiguration
  • CWE-16 Configuration
  • CWE-209 Generation of Error Message Containing Sensitive Information
  • CWE-756 Missing Custom Error Page
  • CIS Benchmarks (OS, container, cloud)