Container Escape with Api Keys
How Container Escape Manifests in API Keys
Container escape vulnerabilities combined with poorly protected API keys create a critical attack chain. An attacker who escapes a container can access host-level secrets or other container secrets if API keys are stored insecurely. Common manifestation patterns include:
- Mounted Host Directories: API keys stored in files on the host (e.g.,
/etc/secrets/api_key.txt) are mounted into containers via Docker-vor KuberneteshostPathvolumes. If the container runs with excessive privileges (e.g.,--privileged), an attacker can traverse out of the container to read the host file directly. - Docker Socket Binding: Mounting
/var/run/docker.sockinto a container (-v /var/run/docker.sock:/var/run/docker.sock) allows container processes to control the Docker daemon. An attacker can launch a new container with the host's secret directory mounted, exfiltrating API keys. - Kubernetes Secret Misconfiguration: Kubernetes Secrets mounted as volumes (
secretKeyRef) are accessible at/var/run/secrets/kubernetes.io/serviceaccount/within the container. If the container runs as root (common in misconfigured pods) or with ahostPathmount pointing to the secret's etcd storage location, escape can lead to direct secret theft. - Shared Kernel Namespaces: Containers sharing the host's PID, network, or mount namespaces (e.g.,
--pid=host) can enumerate processes or mount points on the host, locating API keys stored in environment variables or temporary files.
For example, a vulnerable Docker run command might expose API keys:
docker run -d \
-v /host/secrets:/container/secrets \
-e API_KEY=$(cat /host/secrets/key.txt) \
--privileged \
vulnerable-app:latestHere, the --privileged flag grants the container nearly all host capabilities. If the application has a container escape flaw (e.g., a kernel vulnerability like CVE-2019-5736), the attacker can read /host/secrets/key.txt directly from the host filesystem.
API Keys-Specific Detection
Detecting this issue requires correlating container configuration weaknesses with API key exposure. Manual inspection involves reviewing Dockerfiles, Kubernetes manifests, and cloud configuration for risky patterns:
- Look for
hostPathvolumes in Kubernetes that mount sensitive directories (/etc/secrets,/var/run/secrets) into containers. - Check Docker run commands or Compose files for
-vmounts pointing to host secret locations and--privilegedor--cap-add=SYS_ADMINflags. - Verify container user settings (
USERin Dockerfile,securityContext.runAsUserin Kubernetes) to ensure non-root execution.
Scanning with middleBrick identifies exposed API keys at the runtime layer. When you scan an API endpoint, middleBrick tests for:
- Hardcoded Keys in Responses: Regex patterns matching common API key formats (e.g.,
sk_live_...for Stripe,AIza...for Google) in error messages, JSON responses, or headers. - Environment Variable Leakage: Some frameworks (e.g., older Express.js setups) may dump environment variables in stack traces. middleBrick probes for this by triggering errors.
- Metadata Endpoint Exposure: Cloud provider metadata services (e.g., AWS EC2
http://169.254.169.254/) sometimes contain IAM credentials that can be used to access secret managers. If an API inadvertently proxies or reveals these, it's flagged.
While middleBrick cannot directly see container configurations (black-box scanning), it detects the symptom: API keys that should be secret are exposed via the API. This indicates a broader secret management failure that may include container-related risks. For instance, a finding of "API Key in Error Response" suggests the key might be stored in an environment variable that could be accessible via container escape if the host's secret management is similarly flawed.
Example CLI scan to detect exposed keys:
middlebrick scan https://api.example.com/v1/usersThe report will highlight any exposed keys under "Data Exposure" or "Authentication" categories, with severity based on key sensitivity (e.g., cloud provider keys are critical).
API Keys-Specific Remediation
Remediation focuses on secret management principles that mitigate both API key exposure and container escape risks. Use native features of your container platform and application framework:
- Never Store Secrets in Files Mounted from Host: Instead, use platform-managed secrets. For Docker Swarm, use
docker secret; for Kubernetes, useSecretobjects mounted as volumes or environment variables with strict RBAC. - Avoid Privileged Containers: Drop capabilities and run as non-root. In Docker, use
--cap-drop=ALLand--security-opt=no-new-privileges. In Kubernetes, setsecurityContext.runAsNonRoot: trueandallowPrivilegeEscalation: false. - Use Ephemeral Secrets: Fetch API keys at runtime from a secrets manager (e.g., HashiCorp Vault, AWS Secrets Manager) using IAM roles assigned to the container/pod. This avoids storing keys on disk.
Code Fix Example (Node.js with Docker/Kubernetes):
Vulnerable: Reading a key from a mounted file and setting it as an env var.
// vulnerable-app.js
const fs = require('fs');
const apiKey = fs.readFileSync('/secrets/api_key.txt', 'utf8'); // File mounted from host
process.env.STRIPE_API_KEY = apiKey;
// Later, used in code
const stripe = require('stripe')(process.env.STRIPE_API_KEY);Remediated: Using Kubernetes Secrets as environment variables (declared in manifest) and ensuring the container runs as non-root.
// remediated-app.js
// Key is injected by Kubernetes as env var, not read from file
const stripe = require('stripe')(process.env.STRIPE_API_KEY);Kubernetes manifest snippet:
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
containers:
- name: app
image: secure-app:latest
env:
- name: STRIPE_API_KEY
valueFrom:
secretKeyRef:
name: stripe-secret
key: api-key
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]For Docker without orchestration, use Docker secrets with a minimal container user:
# Dockerfile
FROM node:18-alpine
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
USER nodejs
COPY --chown=nodejs:nodejs . .
CMD ["node", "app.js"]# docker-compose.yml
version: '3.8'
services:
app:
image: secure-app:latest
secrets:
- stripe_api_key
environment:
STRIPE_API_KEY_FILE: /run/secrets/stripe_api_key
secrets:
stripe_api_key:
external: trueThe application reads the key from the file path provided by Docker, which is managed securely by the Docker daemon and not directly mounted from the host filesystem.
Finally, implement runtime monitoring. middleBrick's Pro plan includes continuous monitoring to alert if API keys become exposed again, and its GitHub Action can fail deployments if new findings appear, preventing vulnerable configurations from reaching production.