Container Escape with Jwt Tokens
How Container Escape Manifests in Jwt Tokens
Container escape attacks aim to break out of an isolated runtime (e.g., Docker, containerd) and gain access to the host filesystem or other containers. When JWT tokens are used to authenticate to a container orchestration platform — most commonly the Kubernetes API server — a flaw in JWT validation can grant an attacker privileged API access. With that access the attacker can:
- Create or patch a privileged pod that mounts the host’s root directory (
hostPath: /). - Exec into that pod and run commands on the host.
- Modify privileged service accounts or cluster roles.
The JWT‑specific code paths where this appears are typically:
- Token receipt – the API server extracts the
Authorization: Bearer <token>header. - Signature verification – the server validates the token’s signature using a shared secret or public key.
- Claims validation – checks such as
iss,aud,exp, and custom claims likegroupsorusername. - Authorization mapping – validated claims are mapped to Kubernetes RBAC subjects.
If any of these steps is mis‑implemented, an attacker can forge a token that maps to a system:master or cluster‑admin user. Real‑world examples include:
- Algorithm confusion ("none") – accepting a token with the
alg:noneheader and skipping signature verification (see CVE‑2022-23521 for a Kubernetes‑related token bypass). - KID injection – using the
kidclaim to reference a file path (../../etc/passwd) when the validation library incorrectly treats the key ID as a filesystem path, leading to disclosure of the secret key. - Weak secret / brute‑force – a low‑entropy HMAC secret allows an attacker to compute a valid signature for arbitrary claims.
Once the attacker holds a token that maps to a cluster‑admin, they can issue a request such as:
POST /api/v1/namespaces/default/pods
{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {"name": "escape-pod"},
"spec": {
"containers": [{
"name": "shell",
"image": "alpine",
"command": ["sleep", "3600"],
"volumeMounts": [{ "name": "host", "mountPath": "/host" }]
}],
"volumes": [{ "name": "host", "hostPath": { "path": "/", "type": "Directory" } }]
}
}
Executing a shell in that pod gives the attacker direct read/write access to the host’s filesystem — effectively a container escape.
Jwt Tokens-Specific Detection
Detecting JWT‑related container‑escape risks involves checking both the token handling logic and the configuration of the service that consumes the token. middleBrick’s unauthenticated black‑box scan includes the following checks that surface these issues:
- Authentication check – verifies whether the endpoint accepts a Bearer token without proper signature validation.
- Input Validation check** – probes for algorithm confusion by sending tokens with
alg:noneand modified claims. - Property Authorization check** – ensures that claims such as
iss,aud, and custom role claims are enforced. - Data Exposure check** – looks for token leakage in response headers, error messages, or debug endpoints.
During a scan, middleBrick will:
- Baseline the endpoint with no token to confirm it requires authentication.
- Send a series of crafted JWTs:
- A token with
alg:noneand a payload that sets"groups":["system:masters"]. - A token where the
kidpoints to a traversal path (../../../etc/ssl/private/ca.key). - A token signed with a weak secret (e.g.,
secret) to test brute‑force feasibility. - Analyze responses: any 2xx response that returns privileged data (e.g., list of secrets, ability to create pods) indicates a missing or broken validation step.
- Correlate findings with the LLM/AI Security module if the endpoint also serves an LLM, ensuring that token‑related misconfigurations are not overlooked in AI‑specific contexts.
The scan report will list each finding with:
- Severity (Critical/High/Medium/Low) based on the impact of gaining cluster‑admin privileges.
- Remediation guidance referencing the specific JWT library method that is misused.
- References to relevant CVEs (e.g., CVE‑2022-23521) and OWASP API Security Top 10 items (Broken Authentication, Improper Asset Management).
Because middleBrick requires no agents or credentials, a developer can simply paste the API URL (e.g., https://api.example.com) and receive a prioritized list of JWT‑related risks that could lead to container escape.
Jwt Tokens-Specific Remediation
Fixing JWT validation to prevent privilege escalation and subsequent container escape involves using the library’s verification features correctly and enforcing strict claim checks. Below are language‑specific examples that demonstrate the safe patterns.
Node.js (jsonwebtoken)
Incorrect (vulnerable) code that accepts any token:
const jwt = require('jsonwebtoken');
function auth(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
try {
// ❌ No verification – just decodes
const payload = jwt.decode(token);
req.user = payload;
next();
} catch (err) {
res.status(401).send('Invalid token');
}
}
Correct implementation:
const jwt = require('jsonwebtoken');
const SECRET = process.env.JWT_SECRET; // strong, random value
function auth(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).send('Missing token');
try {
const payload = jwt.verify(token, SECRET, {
// Enforce algorithm – reject "none"
algorithms: ['HS256'],
// Validate standard claims
issuer: 'https://auth.example.com',
audience: 'https://api.example.com',
// Optional: enforce expiration leeway
clockTimestamp: Math.floor(Date.now() / 1000)
});
// Additional application‑specific claims
if (!payload.groups || !payload.groups.includes('system:masters')) {
return res.status(403).send('Insufficient privileges');
}
req.user = payload;
next();
} catch (err) {
// Distinguish token errors from other failures
if (err.name === 'JsonWebTokenError') {
return res.status(401).send('Invalid token');
}
if (err.name === 'TokenExpiredError') {
return res.status(401).send('Token expired');
}
return res.status(400).send('Bad request');
}
}
Python (PyJWT)
Incorrect (vulnerable) code:
import jwt
from flask import request, abort
def require_auth():
auth = request.headers.get('Authorization', '')
if not auth.startswith('Bearer '):
abort(401)
token = auth.split(' ')[1]
# ❌ No verification
payload = jwt.decode(token, options={"verify_signature": False})
request.user = payload
Correct implementation:
import jwt
from flask import request, abort
SECRET = os.environ.get('JWT_SECRET') # must be strong
def require_auth():
auth = request.headers.get('Authorization', '')
if not auth.startswith('Bearer '):
abort(401, 'Missing Bearer token')
token = auth.split(' ')[1]
try:
payload = jwt.decode(
token,
SECRET,
algorithms=['HS256'], # reject "none"
issuer='https://auth.example.com',
audience='https://api.example.com',
leeway=10 # small clock skew tolerance
)
# Enforce custom claim
groups = payload.get('groups', [])
if 'system:masters' not in groups:
abort(403, 'Insufficient privileges')
request.user = payload
except jwt.InvalidTokenError as e:
abort(401, f'Invalid token: {str(e)}')
Additional hardening steps that apply regardless of language:
- Use a strong, randomly generated secret (minimum 32 bytes for HS256) or, preferably, an asymmetric key pair (RS256/ECDSA) where the public key is stored securely and never exposed to clients.
- Rotate secrets periodically and invalidate old tokens via a token revocation list or short expiration times (
exp≤ 15 min) combined with refresh tokens. - Avoid using the
kidheader to reference file paths; if a key ID is needed, map it to a known key identifier in a secure key store. - Log authentication failures (including malformed tokens) and monitor for spikes that may indicate brute‑force or algorithm‑confusion attempts.
- Regularly scan the endpoint with middleBrick (via CLI, GitHub Action, or the MCP Server) to ensure that any regression in JWT handling is caught early.
By applying these fixes, the service will correctly reject forged tokens that attempt to map to privileged Kubernetes subjects, thereby removing the pathway that attackers use to achieve container escape via JWT misuse.
Frequently Asked Questions
Can middleBrick detect a JWT "none" algorithm attack on my API?
alg:none header and a payload that attempts to elevate privileges (e.g., setting groups to ["system:masters"]. If the endpoint accepts the token and returns privileged data, the finding is reported with high severity and guidance to enforce algorithm verification in your JWT library.