DefectDojo is an open-source vulnerability management platform that streamlines the tracking, deduplication, and management of security findings from multiple scanning tools. It provides metrics, reporting, and integration capabilities for security operations and compliance workflows.
# Clone DefectDojo repository
git clone https://github.com/DefectDojo/django-DefectDojo.git
cd django-DefectDojo
# Using docker-compose (recommended for development)
docker-compose up -d
# Access at http://localhost:8000
# Default credentials: admin / admin (change immediately in production)
# Add DefectDojo Helm repository
helm repo add defectdojo https://defectdojo.github.io/helm-charts
helm repo update
# Install DefectDojo
helm install defectdojo defectdojo/defectdojo \
--namespace defectdojo \
--create-namespace \
--values values.yaml
# Forward port for access
kubectl port-forward -n defectdojo svc/defectdojo 8000:8000
# Clone repository
git clone https://github.com/DefectDojo/django-DefectDojo.git
cd django-DefectDojo
# Install dependencies
pip install -r requirements.txt
# Initialize database
python manage.py migrate
# Create superuser
python manage.py createsuperuser
# Collect static files
python manage.py collectstatic --noinput
# Run development server
python manage.py runserver
# Environment variables (.env)
DEBUG=False
SECRET_KEY=your-secret-key-here
DB_ENGINE=django.db.backends.postgresql
DB_NAME=defectdojo
DB_USER=defectdojo
DB_PASSWORD=secure-password
DB_HOST=postgres
ALLOWED_HOSTS=localhost,127.0.0.1,your-domain.com
- Change default admin password
- Configure authentication (LDAP, OAuth, SAML)
- Set up notification channels (email, Slack, etc.)
- Create product types and templates
- Configure scanner credentials
- Set up system settings and SLA policies
| Level | Purpose | Description |
|---|
| Product | Container | High-level application or service |
| Engagement | Testing cycle | Time-bound security testing activity |
| Test | Scan result | Individual scanner output within engagement |
| Finding | Vulnerability | Specific security issue or flaw |
Dashboard → Products → New Product
- Product Name
- Product Type (Web App, API, Mobile, etc.)
- Description
- SLA choice
- Enable/disable various tracking options
Product → New Engagement
- Engagement Name
- Engagement Type (Baseline, Targeted, Incident, etc.)
- Start Date
- End Date (optional, for scoped tests)
- Lead
- Status (Scheduled, In Progress, Completed, etc.)
- Engagement Type Template (optional)
Engagement → Add Test
- Test Type (Nessus, Burp, OWASP ZAP, Trivy, etc.)
- Scan Date
- Environment (Development, Staging, Production)
- Scan Status
- Upload findings via file or API
| Scanner | Format | Notes |
|---|
| Nessus | .nessus XML | Network vulnerability scanner |
| Burp Suite | Burp XML | Web application security |
| OWASP ZAP | XML/JSON | Dynamic web app scanning |
| Trivy | JSON/SARIF | Container/artifact scanning |
| Nuclei | JSON | Fast vulnerability scanner |
| Sonarqube | JSON | Code quality & SAST |
| Checkmarx | XML | Enterprise SAST |
| Fortify | FPR/XML | Static security analysis |
| Snyk | JSON | Open source vulnerability |
| Qualys | XML | Vulnerability management |
# Web UI Import
Engagement → Test → Import Scan Results
- Select Parser (auto-detected)
- Upload scan file
- Verify deduplication settings
- Confirm import
# API Import
curl -X POST \
-H "Authorization: Token YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d @scan-results.json \
http://localhost:8000/api/v2/import-scan/
# Using API for multiple scans
for file in scans/*.xml; do
curl -X POST \
-H "Authorization: Token YOUR_API_TOKEN" \
-F "file=@$file" \
-F "test=TEST_ID" \
http://localhost:8000/api/v2/import-scan/
done
Settings → System Settings → Deduplication
- Enable/disable deduplication
- Hash algorithm (MD5, SHA256)
- Manual deduplication mode
- Clustering method
Product → Findings
- Select multiple findings
- Merge duplicates
- Keep one as primary
- Link duplicates
- Update status consistently
DefectDojo automatically creates hashes from:
- File path + line number + CWE
- Endpoint + parameter
- IP + port + issue type
Duplicate findings are grouped and displayed together.
Finding → Actions → Accept Risk
- Risk Acceptance Name
- Justification/Reason
- Decision Date
- Expiration Date (optional)
- Accepted by (user)
- Recommended/Required fields
Product → Findings → Select Multiple
- Bulk Actions → Accept Risk
- Apply same justification to all
- Set expiration policy
Product → Metrics → Risk Acceptance
- View accepted vs. open findings
- Export risk acceptance summary
- Track acceptance history
- Monitor expiration dates
| Metric | Purpose |
|---|
| Open Vulnerabilities | Current unfixed findings |
| Fixed Vulnerabilities | Resolved issues (30/60/90 day) |
| Average CVSS Score | Risk severity trending |
| Findings by Severity | Critical/High/Medium/Low breakdown |
| Remediation Rate | Percentage of closed findings |
| Mean Time to Remediation | Average fix duration |
Product → Reports → Generate Report
- Report Type (Detailed, Executive, Compliance)
- Date Range
- Include: Findings, Metrics, Risk Acceptance
- Export Format (PDF, Excel, JSON)
- Schedule recurring reports
Settings → Report Templates
- Create custom report layout
- Select sections/widgets
- Add company branding
- Define data filters
- Schedule automated delivery
# Generate API token
Settings → API Tokens → Create Token
# Use in requests
curl -H "Authorization: Token YOUR_API_TOKEN" \
http://localhost:8000/api/v2/products/
# List products
GET /api/v2/products/
# Get product details
GET /api/v2/products/{id}/
# List engagements for product
GET /api/v2/engagements/?product={product_id}
# List findings
GET /api/v2/findings/?product={product_id}&status=Open
# Create finding
POST /api/v2/findings/
{
"title": "SQL Injection",
"test": 123,
"severity": "High",
"cwe": 89
}
# Update finding
PATCH /api/v2/findings/{id}/
# Import scan results
POST /api/v2/import-scan/
# All API endpoints support pagination
GET /api/v2/findings/?limit=50&offset=0
# Get total count
GET /api/v2/findings/?limit=1
# Returns: count: 12345
// Jenkinsfile
pipeline {
stages {
stage('Security Scan') {
steps {
sh './zap-scan.sh'
sh 'curl -X POST \
-H "Authorization: Token ${DEFECTDOJO_TOKEN}" \
-F "file=@zap-report.xml" \
-F "test=123" \
http://defectdojo.example.com/api/v2/import-scan/'
}
}
}
}
name: Security Scan
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Trivy scan
run: trivy image --format json -o trivy-report.json myimage:latest
- name: Upload to DefectDojo
run: |
curl -X POST \
-H "Authorization: Token ${{ secrets.DEFECTDOJO_TOKEN }}" \
-F "file=@trivy-report.json" \
-F "test=${{ env.TEST_ID }}" \
${{ secrets.DEFECTDOJO_URL }}/api/v2/import-scan/
stages:
- security
sast_scan:
image: aquasec/trivy:latest
stage: security
script:
- trivy image --format json -o report.json $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- |
curl -X POST \
-H "Authorization: Token $DEFECTDOJO_TOKEN" \
-F "file=@report.json" \
-F "test=$TEST_ID" \
$DEFECTDOJO_URL/api/v2/import-scan/
Settings → Integrations → JIRA
- JIRA URL
- Username/Token
- Project Key
- Issue Type (Bug, Task, etc.)
- Custom field mapping
Finding → Actions → Create JIRA Issue
- Auto-creates ticket with:
- Finding title & description
- Severity mapped to priority
- CWE & CVSS details
- Link back to DefectDojo
Product → Findings → Select Multiple
- Bulk Actions → Create JIRA Issues
- Apply same priority/assignment
- Template comments
Settings → Integrations → JIRA
- Enable bi-directional sync
- Auto-close finding when ticket resolved
- Update finding when ticket status changes
Settings → System Settings → SLA
- Define SLA for each severity:
- Critical: 7 days
- High: 30 days
- Medium: 60 days
- Low: 90 days
Product → Metrics → SLA Status
- View findings past SLA
- Identify aging vulnerabilities
- Generate SLA breach reports
- Track remediation trends
| Severity | Recommended SLA |
|---|
| Critical | 7 days |
| High | 14-30 days |
| Medium | 30-60 days |
| Low | 60-90 days |
| Role | Permissions |
|---|
| Admin | Full system access, user management, settings |
| Product Owner | Product management, engagement creation, finding updates |
| Analyst | View/edit findings, run reports, comment |
| Reporter | View-only access, report generation |
| Service Account | API-only access, limited scopes |
Settings → Permissions → Roles
- Define role name
- Select permissions:
- View products
- Add findings
- Accept risk
- Create engagements
- Export reports
- Manage users
Product → Settings → Permissions
- Product Owner
- Analysts (multiple)
- Stakeholders (view-only)
- JIRA project leads
Settings → Users → Select User
- Global role (Admin, Product Owner, etc.)
- Product-specific role
- Engagement-level access
- API token scopes
- Review & Deduplicate: Consolidate duplicate findings immediately after import
- Set Severity: Ensure accurate CVSS/severity classification
- Add Context: Document root cause and remediation steps
- Track Progress: Update status (Open, In Progress, Fixed, Accepted)
- Verify Fixes: Re-scan after remediation to confirm closure
- Baseline Tests: Initial comprehensive assessment
- Targeted Tests: Focus on specific components/changes
- Regression Tests: Verify previous fixes weren’t reintroduced
- Incident Testing: Rapid assessment after security events
- Executive Reports: Metrics, trends, risk summary
- Technical Reports: Detailed findings, remediation guidance
- Compliance Reports: Evidence for audits, certifications
- SLA Reports: Remediation tracking, aging vulnerabilities
- Automate Imports: Schedule scans to auto-import results
- Notify Teams: Set up alerts for critical findings
- JIRA Workflow: Automatic ticket creation and sync
- API Usage: Extract data for custom dashboards
| Issue | Solution |
|---|
| Import fails | Verify scanner format, check parser compatibility, validate XML |
| Slow deduplication | Disable hash-based dedup, perform manual cleanup |
| API rate limits | Implement backoff, batch requests, upgrade rate limits |
| Memory issues | Increase Java heap, reduce bulk operations size |
| LDAP auth fails | Verify credentials, check LDAP config, test connection |
# Check system status
docker-compose logs defectdojo
# Clear old findings (bulk cleanup)
python manage.py shell
>>> Finding.objects.filter(date__lt='2023-01-01').delete()
# Reset admin password
python manage.py changepassword admin
# Backup database
pg_dump defectdojo > backup.sql