Insecure Defaults

Unsafe DefaultsDefault Misconfigurations

Insecure Defaults at a glance

What it is: Security weaknesses caused by shipping or deploying with default settings that are not safe for production.
Why it happens: Insecure defaults occur when development or permissive configurations are deployed to production, relying on weak platform, proxy, or middleware settings that expose excessive access or capabilities.
How to fix: Explicitly harden runtime and framework settings, run containers as non-root with minimal privileges, and secure CORS, cookies, and headers by removing unnecessary exposure.

Overview

Many frameworks and platforms ship with defaults that favor ease of use. In production these defaults can increase impact or leak information. Examples include running containers as root, permissive CORS libraries enabled with a one-liner, cookies set without Secure when TLS is terminated upstream, default tokens mounted into Kubernetes pods, and servers that reveal their exact versions.

sequenceDiagram participant Browser participant App as App Container participant Host as Node Browser->>App: Trigger RCE in web handler App-->>Browser: Shell with root uid inside container App->>Host: Write to mounted /data volume as root note over App,Host: Running as root turns a minor RCE into a persistent foothold
A potential flow for a Insecure Defaults exploit

Where it occurs

It occurs when development or platform defaults are used in production, such as permissive middleware, weak identity settings, or insecure HTTPS and capability configurations.

Impact

The impact ranges from session theft and CSRF bypass to cluster-wide compromise after a container breakout. Even when no direct exploit is present, information disclosure accelerates targeted attacks.

Prevention

Prevent insecure defaults by applying platform-specific hardening baselines, enforcing safe cookie and CORS settings, running containers as non-root, limiting Kubernetes RBAC and tokens, hiding server versions, and automating CI checks for weak configs.

Examples

Switch tabs to view language/framework variants.

Docker image runs as root by default, enabling high-impact escapes

If the image does not set a non-root user, the app runs as root inside the container. Breakouts or volume writes can be far worse.

Vulnerable
Dockerfile • Docker — Bad
FROM node:20
WORKDIR /app
COPY . /app
RUN npm ci --only=production
CMD ["node","server.js"]
  • Line 1: No USER set, process runs as root

Containers default to root if a USER is not set. Root inside the container increases impact of any RCE and interacts badly with mounted volumes.

Secure
Dockerfile • Docker — Good
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# create non-root user and drop caps
RUN useradd -m appuser && mkdir -p /app && chown -R appuser:appuser /app
USER appuser
# optionally drop capabilities at runtime
# docker run --cap-drop=ALL --read-only -v /app/tmp -p 3000:3000 app:latest
CMD ["node","server.js"]
  • Line 6: Create and switch to a non-root user and drop capabilities

Run as a dedicated unprivileged user, drop capabilities, use read-only filesystems and minimal images.

Engineer Checklist

  • Run containers as non-root and drop Linux capabilities

  • Disable automount of Kubernetes service account tokens unless required

  • Configure reverse proxy awareness and set cookie Secure, HttpOnly, and SameSite

  • Restrict CORS to known origins and avoid credentials unless necessary

  • Disable server version banners and review response headers

  • Add CI checks to detect insecure defaults before deploy

End-to-End Example

A Node app is packaged in a Docker image without setting a USER, then deployed to Kubernetes. The pod auto-mounts a service account token. An attacker finds a trivial RCE in an endpoint. Because the app runs as root, the attacker writes a cron-like script into a host-mounted volume and uses the mounted token to list secrets.

Vulnerable
DOCKERFILE
# VULNERABLE: Dockerfile with insecure defaults
# Dockerfile

FROM node:18

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

# VULNERABLE: No USER directive!
# Container runs as root (uid 0) by default
# If compromised, attacker has root access inside container

EXPOSE 3000

# VULNERABLE: Running as root user
CMD ["node", "server.js"]

# VULNERABLE: Kubernetes deployment with insecure defaults
# deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      # VULNERABLE: No automountServiceAccountToken: false
      # Service account token auto-mounted at /var/run/secrets/kubernetes.io/serviceaccount
      # Allows API access if container compromised!
      
      # VULNERABLE: No securityContext restrictions
      # Allows privileged escalation, running as root, etc.
      
      containers:
      - name: app
        image: myapp:latest
        ports:
        - containerPort: 3000
        # VULNERABLE: No securityContext on container level
        # No runAsNonRoot, no readOnlyRootFilesystem
        # No capability drops

# VULNERABLE: Node.js/Express with insecure cookie defaults

const session = require('express-session');

app.use(session({
  secret: 'my-secret',
  resave: false,
  saveUninitialized: false,
  cookie: {
    // VULNERABLE: No 'secure' flag!
    // Cookie sent over HTTP, can be intercepted
    // secure: true,  // MISSING!
    
    // VULNERABLE: No httpOnly!
    // httpOnly: true,  // MISSING! XSS can steal cookie
    
    // VULNERABLE: No sameSite!
    // sameSite: 'strict',  // MISSING! CSRF possible
    
    maxAge: 24 * 60 * 60 * 1000
  }
}));

// VULNERABLE: Permissive CORS with default settings
const cors = require('cors');

// VULNERABLE: Allows ALL origins!
app.use(cors({
  origin: true,  // Reflects any origin!
  credentials: true  // Allows authenticated requests from ANY origin!
}));
// This enables CSRF from any malicious site

// VULNERABLE: Nginx with version disclosure
# nginx.conf

http {
  # VULNERABLE: server_tokens defaults to 'on'
  # Exposes exact nginx version in error pages and headers
  # Server: nginx/1.18.0
  
  server {
    listen 80;
    
    # VULNERABLE: No HTTPS enforcement
    # Allows plaintext traffic, cookies sent over HTTP
    
    location / {
      proxy_pass http://backend:3000;
      
      # VULNERABLE: No security headers
      # Missing X-Content-Type-Options, X-Frame-Options, etc.
    }
  }
}

// VULNERABLE: ASP.NET Core cookie defaults

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie(options => {
    // VULNERABLE: Cookie.SecurePolicy defaults to None
    // Cookies sent over HTTP!
    // options.Cookie.SecurePolicy = CookieSecurePolicy.Always;  // MISSING!
    
    // VULNERABLE: No SameSite protection
    // options.Cookie.SameSite = SameSiteMode.Strict;  // MISSING!
    
    options.ExpireTimeSpan = TimeSpan.FromHours(24);
  });

// VULNERABLE: Default database connection allows any IP
# PostgreSQL pg_hba.conf

# VULNERABLE: Allows connections from anywhere!
host    all    all    0.0.0.0/0    md5
# Should restrict to specific IPs or use stronger auth

// VULNERABLE: Express trust proxy not configured
// When behind a reverse proxy (common in production)

// VULNERABLE: Not trusting proxy
// app.set('trust proxy', true);  // MISSING!
// Results in req.ip showing proxy IP, not client IP
// req.protocol shows 'http' even when proxy uses HTTPS
// Cookie secure flag won't work correctly!
Secure
DOCKERFILE
# SECURE: Dockerfile with hardened defaults
# Dockerfile

FROM node:18-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

# Multi-stage build - smaller, more secure image
FROM node:18-alpine

WORKDIR /app

# SECURE: Create non-root user
RUN addgroup -g 1001 -S appgroup && \
    adduser -S appuser -u 1001 -G appgroup

# Copy only production dependencies and code
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --chown=appuser:appgroup . .

# SECURE: Switch to non-root user
USER appuser

EXPOSE 3000

# Run as non-root
CMD ["node", "server.js"]

# SECURE: Kubernetes deployment with hardened defaults
# deployment.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: web-app-sa
automountServiceAccountToken: false  # SECURE: Disable auto-mount

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      # SECURE: Use dedicated service account with minimal permissions
      serviceAccountName: web-app-sa
      
      # SECURE: Disable token auto-mount at pod level
      automountServiceAccountToken: false
      
      # SECURE: Pod-level security context
      securityContext:
        runAsNonRoot: true
        runAsUser: 1001
        fsGroup: 1001
        seccompProfile:
          type: RuntimeDefault
      
      containers:
      - name: app
        image: myapp:latest
        ports:
        - containerPort: 3000
        
        # SECURE: Container-level security context
        securityContext:
          allowPrivilegeEscalation: false
          runAsNonRoot: true
          runAsUser: 1001
          readOnlyRootFilesystem: true
          capabilities:
            drop:
              - ALL
        
        # SECURE: Resource limits
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 250m
            memory: 256Mi
        
        # SECURE: Writable volume for temp files
        volumeMounts:
        - name: tmp
          mountPath: /tmp
      
      volumes:
      - name: tmp
        emptyDir: {}

# SECURE: Node.js/Express with secure cookie settings

const session = require('express-session');

// SECURE: Configure trust proxy
app.set('trust proxy', 1);  // Trust first proxy

app.use(session({
  secret: process.env.SESSION_SECRET,  // From env, not hardcoded
  resave: false,
  saveUninitialized: false,
  name: 'sessionId',  // Don't use default 'connect.sid'
  cookie: {
    secure: true,        // SECURE: Only over HTTPS
    httpOnly: true,      // SECURE: No JavaScript access
    sameSite: 'strict',  // SECURE: CSRF protection
    maxAge: 3600000,     // 1 hour
    domain: '.example.com'
  }
}));

// SECURE: Restrictive CORS configuration
const cors = require('cors');

const ALLOWED_ORIGINS = [
  'https://app.example.com',
  'https://www.example.com'
];

app.use(cors({
  origin: (origin, callback) => {
    // Allow requests with no origin (mobile apps, Postman, etc.)
    if (!origin) return callback(null, true);
    
    if (ALLOWED_ORIGINS.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  credentials: true,  // Only with specific origins
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  maxAge: 86400  // 24 hours
}));

// SECURE: Security headers middleware
const helmet = require('helmet');

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", "data:", "https:"],
    },
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  },
  frameguard: { action: 'deny' },
  noSniff: true,
  xssFilter: true
}));

// Hide X-Powered-By header
app.disable('x-powered-by');

// SECURE: Nginx with hardened defaults
# nginx.conf

http {
  # SECURE: Disable version disclosure
  server_tokens off;
  
  # Security headers
  add_header X-Frame-Options "DENY" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-XSS-Protection "1; mode=block" always;
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;
  
  # Rate limiting
  limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
  limit_req_status 429;
  
  # Redirect HTTP to HTTPS
  server {
    listen 80;
    server_name app.example.com;
    return 301 https://$server_name$request_uri;
  }
  
  # HTTPS server
  server {
    listen 443 ssl http2;
    server_name app.example.com;
    
    # TLS configuration
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
    location / {
      limit_req zone=general burst=20 nodelay;
      
      proxy_pass http://backend:3000;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
    }
  }
}

// SECURE: ASP.NET Core with secure cookie policy

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie(options => {
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;  // HTTPS only
    options.Cookie.SameSite = SameSiteMode.Strict;  // CSRF protection
    options.Cookie.HttpOnly = true;  // No JS access
    options.Cookie.Name = "AppAuth";  // Custom name
    options.ExpireTimeSpan = TimeSpan.FromHours(1);
    options.SlidingExpiration = true;
  });

// SECURE: Database connection restrictions
# PostgreSQL pg_hba.conf

# Only allow specific IPs
host    all    all    10.0.1.0/24    scram-sha-256
host    all    all    192.168.1.100/32    scram-sha-256

# Require SSL
hostssl    all    all    0.0.0.0/0    scram-sha-256

Discovery

This vulnerability is discovered by identifying default credentials, configurations, or settings that remain unchanged in production, such as default admin passwords, enabled debug modes, or permissive security settings.

  1. 1. Check container user privileges

    http

    Action

    Inspect container runtime configuration to identify if process runs as root

    Request

    CLI N/A - Analysis or internal step

    Response

    Status: 200
    Body:
    {
      "note": "No runAsNonRoot or runAsUser specified, defaulting to root (uid 0)"
    }

    Artifacts

    pod_security_context
  2. 2. Verify service account token automount

    http

    Action

    Check if Kubernetes service account tokens are automatically mounted into pods

    Request

    CLI N/A - Analysis or internal step

    Response

    Status: 200
    Body:
    {
      "note": "Service account token, ca.crt, and namespace files present and readable"
    }

    Artifacts

    mounted_secrets token_content
  3. 3. Test cookie security flags

    http

    Action

    Inspect session cookies to verify Secure, HttpOnly, and SameSite attributes

    Request

    GET https://app.example.com/login

    Response

    Status: 200
    Body:
    {
      "note": "Set-Cookie header missing Secure flag despite HTTPS, enabling MITM attacks"
    }

    Artifacts

    http_response_headers cookie_attributes
  4. 4. Check CORS policy permissiveness

    http

    Action

    Send cross-origin request to test if CORS allows any origin with credentials

    Request

    OPTIONS https://api.example.com/data
    Headers:
    Origin: https://evil.example.com

    Response

    Status: 200
    Body:
    {
      "note": "Response includes Access-Control-Allow-Origin: * with Allow-Credentials: true"
    }

    Artifacts

    cors_headers

Exploit steps

An attacker exploits this by using well-known default credentials or leveraging insecure default configurations to gain unauthorized access, escalate privileges, or bypass security controls without sophisticated exploitation techniques.

  1. 1. Escape container using root privileges

    Mount host filesystem from root container

    http

    Action

    Exploit root permissions to mount host filesystem and write to persistent storage

    Request

    CLI N/A - Analysis or internal step

    Response

    Status: 200
    Body:
    {
      "note": "Host filesystem mounted, SSH backdoor installed on underlying node"
    }

    Artifacts

    mount_output file_write_confirmation
  2. 2. Enumerate cluster resources with service account

    Query Kubernetes API for secrets

    http

    Action

    Use auto-mounted service account token to list secrets and configmaps across namespaces

    Request

    CLI N/A - Analysis or internal step

    Response

    Status: 200
    Body:
    {
      "note": "Cluster secrets enumerated including DB passwords and API keys"
    }

    Artifacts

    kubernetes_secrets api_response
  3. 3. Steal session cookies via missing Secure flag

    MITM attack to capture cookies

    browser

    Action

    Downgrade HTTPS to HTTP to capture session cookies lacking Secure attribute

    Request

    GET http://app.example.com/dashboard

    Response

    Status: 200
    Body:
    {
      "note": "Session cookie transmitted over HTTP, captured by network attacker"
    }

    Artifacts

    captured_cookies session_token
  4. 4. Cross-site request forgery via permissive CORS

    Execute authenticated requests from malicious origin

    browser

    Action

    Leverage wildcard CORS to make authenticated API calls from attacker-controlled site

    Request

    POST https://api.example.com/transfer
    Headers:
    Origin: https://evil.example.com
    Content-Type: application/json
    Body:
    {
      "amount": 1000,
      "to": "attacker"
    }

    Response

    Status: 200
    Body:
    {
      "note": "Cross-origin request succeeds with user credentials, money transferred"
    }

    Artifacts

    transaction_record cors_response_headers

Specific Impact

Running as root turns a minor exploit into a high impact incident. The attacker persists on a shared volume and enumerates the cluster using the auto-mounted token. If the token has broad RBAC, they can create pods, read secrets, or move laterally.

Fixing only the application bug would not remove the backdoor or revoke the stolen cluster token, so recovery is longer and costlier.

Fix

Harden platform defaults. Run as an unprivileged user and drop capabilities. Disable token auto-mount and use least privilege RBAC or workload identity. Configure proxy awareness and set cookie flags explicitly. Restrict CORS to trusted origins. Add CI checks that fail builds if these defaults are missing.

Detect This Vulnerability in Your Code

Sourcery automatically identifies insecure defaults vulnerabilities and many other security issues in your codebase.

Scan Your Code for Free