iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

A05 Security Misconfiguration

A05:2021 — Security Misconfiguration — covers default credentials, verbose errors, unnecessary features, missing security headers, outdated software. The bug class where humans fail, not code.

Defaults, headers, secrets, scan

EXAMPLE
# A05 is the most common real-world finding in pen-tests. The fix is process, not code.

# === Common misconfigurations ===

# 1) Default credentials
# - admin / admin on the firewall
# - root / root on MongoDB without auth
# - postgres user with no password
# - Tomcat manager / Tomcat manager
# - Elasticsearch with no auth on port 9200
#
# Fix:
#   - Rotate ALL defaults at install
#   - Enforce password requirements
#   - Use SSO / OIDC for admin tools when possible
#   - Disable default accounts you don't use

# 2) Verbose error messages in production
# Bad: stack trace, SQL query, file path leaked to attacker
app.use((err, req, res, next) => {
    res.status(500).send(err.stack);     # NEVER in production
});

# Good
app.use((err, req, res, next) => {
    log.error({ err, reqId: req.id }, 'unhandled');
    res.status(err.status ?? 500).json({
        error: process.env.NODE_ENV === 'production' ? 'internal' : err.message,
        requestId: req.id,
    });
});

# 3) Missing security headers
import helmet from 'helmet';

app.use(helmet({
    contentSecurityPolicy: {
        directives: {
            defaultSrc: ["'self'"],
            scriptSrc:  ["'self'", "'nonce-RANDOM'"],
            styleSrc:   ["'self'", "'nonce-RANDOM'"],
            imgSrc:     ["'self'", 'data:', 'https:'],
            objectSrc:  ["'none'"],
            baseUri:    ["'self'"],
        },
    },
    hsts: { maxAge: 31_536_000, includeSubDomains: true, preload: true },
    xFrameOptions: { action: 'deny' },
}));

# Or set manually:
res.setHeader('Strict-Transport-Security',  'max-age=31536000; includeSubDomains; preload');
res.setHeader('X-Content-Type-Options',     'nosniff');
res.setHeader('Referrer-Policy',            'strict-origin-when-cross-origin');
res.setHeader('Permissions-Policy',         'camera=(), microphone=(), geolocation=()');
res.setHeader('X-Frame-Options',            'DENY');
res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');

# Test with: securityheaders.com

# 4) Unnecessary features enabled
# - PHP eval enabled
# - Directory listing on web server
# - Sample apps / docs accessible (e.g. /phpinfo.php, Tomcat docs)
# - Debug endpoints (/debug, /healthcheck with sensitive info)
# - GraphQL introspection on prod
# - HTTP TRACE method enabled (XST attacks)

nginx.conf — disable directory listing
# autoindex off;

# Apache
# Options -Indexes

# 5) Outdated software / dependencies
# Track + patch:
#   - OS packages (apt / yum updates)
#   - Base Docker images (rebuild monthly minimum)
#   - npm / pip / cargo deps (Renovate, Dependabot)
#   - Application servers + runtimes
#   - Web framework versions

# Automate:
#   - Renovate / Dependabot for code deps
#   - Trivy / Snyk for image + dep scanning in CI
#   - Patch SLA: critical < 7 days, high < 30, medium < 90

# 6) Open admin / debug ports
ss -tlnp        # list listening services
# Internal: 6379 Redis, 5432 Postgres, 27017 Mongo, 9200 Elastic, 9090 Prom
# These should ONLY listen on localhost or VPC.

# nginx — only listen on localhost
listen 127.0.0.1:8080;

# Docker — bind to 127.0.0.1, not 0.0.0.0
docker run -d -p 127.0.0.1:5432:5432 postgres

# Kubernetes — don't expose admin services with type=LoadBalancer

# 7) Secrets in source / config files
# .env committed to git
# config.yml with passwords
# Dockerfile with ENV API_KEY=...
# JS source with apiKey hard-coded

# Fix:
#   - gitleaks / trufflehog in pre-commit + CI
#   - Use KMS / Secrets Manager / Vault
#   - Rotate any leaked secret at source (force-push is NOT enough)
#   - Use OIDC-assumed roles instead of long-lived API keys where possible

# 8) Permissive S3 / cloud bucket policies
# Common pattern: public bucket meant to be private
# - 'AmazonS3FullAccess' on a Lambda role that needs s3:GetObject
# - 'Allow': '*' on Resource
# - Public read on a backup bucket

# Fix:
#   - Block Public Access at account level
#   - IAM Access Analyzer to find externally-accessible resources
#   - Periodic cloud security posture review (ScoutSuite, Prowler)

# 9) Insecure cookies
res.cookie('session', sid);                              # missing flags!
res.cookie('session', sid, {                              # correct
    httpOnly: true,
    secure:   true,
    sameSite: 'lax',
});

# 10) CORS misconfiguration
# Bad: 'Access-Control-Allow-Origin': '*' with 'Allow-Credentials: true' → browsers reject, but server is wrong anyway
# Bad: Reflecting Origin without allowlist:
app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', req.headers.origin);    # trusts attacker!
    res.header('Access-Control-Allow-Credentials', 'true');
    next();
});

# Good:
import cors from 'cors';
app.use(cors({
    origin: (origin, cb) => cb(null, ALLOWED.has(origin ?? '')),
    credentials: true,
}));

# 11) Default error pages
# Express default 404 / 500 leak framework name + version.
# Fix: register custom handlers.

# 12) Sample / scaffold code shipped to prod
# - Express generator's debug routes
# - Spring's actuator endpoints exposed to internet
# - Django admin reachable without IP allowlist
# - WordPress admin without 2FA

# Fix: review what's reachable from the internet; restrict.

# === Detection ===

# 13) Automated scanning
#   - Mozilla Observatory          (security headers, TLS, redirects)
#   - securityheaders.com           (security headers only)
#   - SSL Labs                      (TLS configuration)
#   - OWASP ZAP                     (web app scanner)
#   - Nuclei + community templates  (CVE + misconfig)
#   - testssl.sh                    (TLS scanner)
#   - kube-bench / kube-hunter      (Kubernetes)
#   - Trivy / Snyk                   (image + dep scanning)

# 14) Cloud-native tools
#   - AWS Config + Trusted Advisor
#   - GCP Security Command Center
#   - Azure Defender
#   - CloudSploit, Prowler, ScoutSuite (multi-cloud)

# 15) Static analysis
#   - Semgrep with security packs
#   - Checkov (IaC misconfig)
#   - tfsec (Terraform-specific)
#   - kics (multi-IaC scanner)

# === Process ===

# 16) Configuration as code
#   - Terraform / CloudFormation / Pulumi for cloud
#   - Kustomize / Helm for Kubernetes
#   - Docker for app config
# Reproducible, reviewable, auditable.

# 17) Hardening baselines
#   - CIS Benchmarks (Linux, Kubernetes, AWS, Docker, Postgres, ...)
#   - NIST SP 800-53 / 800-171 controls
#   - Pre-built hardened AMIs / images

# 18) Patch management policy
# - Critical: 7 days
# - High: 30 days
# - Medium: 90 days
# - Low: best-effort

# Automate where possible:
#   - Ubuntu unattended-upgrades for OS
#   - Renovate / Dependabot for code
#   - Reusable workflows in CI for rebuilding base images

# 19) Periodic security review
#   - Quarterly external attack surface review
#   - Annual third-party pen test
#   - Continuous bug bounty for high-risk products
#   - Quarterly access review (who has what?)

# === Real-world incidents ===

# Misconfig examples that became breaches:
#   - Capital One 2019: misconfigured WAF + SSRF → S3 data exposed
#   - MongoDB exposed without auth → mass deletion / ransomware
#   - Elasticsearch with no auth → millions of records leaked
#   - Default Tomcat credentials → RCE on production servers
#   - Verbose error → SQL injection point + DB schema leaked
#   - Hardcoded secrets in mobile app APK → backend credentials stolen

# === Best practices ===
#   ✅ Disable / change defaults immediately on every service
#   ✅ Lock down error verbosity in production
#   ✅ Ship strong security headers via middleware
#   ✅ Patch on a schedule with SLA
#   ✅ Configuration as code (no manual prod tweaks)
#   ✅ Periodic scans (CI + scheduled)
#   ✅ Secrets in a manager, not in code
#   ✅ Least privilege at every layer (cloud, app, DB)
#   ✅ Minimise the public surface — internal services on private networks only

Why it matters

Misconfiguration is the most common real-world vuln — default creds, verbose errors, missing headers. The fix is process: IaC, automated scanning, patch SLAs, periodic reviews. Code review catches XSS; checklists catch this.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// A05 Security Misconfiguration — open S3 buckets, default creds, verbose errors.
// Fix: IaC scanners (tfsec, checkov, kube-score), CIS benchmarks, immutable infra.
Try it Yourself »

Discussion

Loading…