"DefectDojo tells you what's wrong. Our graph engine tells you why it matters."
A cloud-native security risk platform that ingests findings from Prowler (AWS + GitHub), enriches them with threat-intel (CISA KEV + EPSS), and scores each asset using graph-traversal blast-radius analysis — all visualised in a custom dashboard backed by Neo4j.
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
│ │ CARTOGRAPHY │ │ PROWLER │ │ PROWLER │ │
│ │ AWS discovery│ │ AWS scan │ │ GitHub scan │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────┬────────────┘ │
│ │ direct write │ OCSF JSON │ OCSF JSON │
│ ▼ ▼ ▼ │
│ [ NEO4J ] [ DEFECTDOJO ] ◀── import_github.py │
│ ▲ │ │
│ │ bridge.py ◀───┘ (match findings → asset nodes) │
│ │ │
│ ├── enrichers.py (CISA KEV + EPSS) │
│ ├── risk_engine.py (blast-radius graph scoring) │
│ │ │
│ └──▶ Custom Dashboard :8888 (pipeline UI + graphs) │
│ Synapse Assistant (AI Chatbot inside Dashboard) │
│ DefectDojo UI :8080 │
│ Neo4j Browser :7474 │
│ │
│ engine/runner.py (host, port 9999) ◀── dashboard pipeline buttons │
└─────────────────────────────────────────────────────────────────────────┘
| Tool | Version | Notes |
|---|---|---|
| Docker + Docker Compose | v24+ | All services run in containers |
| Python | 3.11+ | For the pipeline scripts and runner |
| GitHub PAT | any | repo + read:org scopes — only needed for GitHub scanning |
Follow these exact steps to deploy the platform from scratch on a new machine:
git clone <your-github-repo-url>
cd risk-platformYou must create a .env file before running any setup scripts. A safe .env.example template is provided in the repository.
cp .env.example .envOpen .env in your text editor and configure the following mandatory fields based on your environment:
# REQUIRED CORE CONFIG
AWS_ACCOUNT_ID="123456789012" # Your 12-digit AWS Account ID
AWS_DEFAULT_REGION="us-east-1" # Your AWS region
# REQUIRED API KEYS
# (You can also leave these blank and configure them later from the ⚙ Account Setup UI)
AWS_ACCESS_KEY_ID="AKIA..."
AWS_SECRET_ACCESS_KEY="..."
GITHUB_TOKEN="ghp_..." # Needs `repo` + `read:org` scopes
SYNAPSE_ASSISTANT_KEY="gsk_..." # Groq API key for the Synapse Assistant
# SECURITY PASSWORDS
# Change these from their defaults if deploying to a production server
NEO4J_PASSWORD="changeme123"
DOJO_ADMIN_PASSWORD="admin"Note: Leave
DOJO_API_TOKENblank! The setup script will fetch and save it automatically.
chmod +x setup.sh
./setup.shThe script handles everything in order:
- Checks prerequisites (Docker, Python 3.11+, curl)
- Validates the GitHub token (if set in
.env) - Creates the Python virtualenv and installs all dependencies
- Starts all Docker services (
docker compose up -d --build) - Waits for Neo4j, DefectDojo, and the dashboard to be healthy
- Fetches the DefectDojo API token and writes it back to
.envautomatically - Starts the host-side pipeline runner on port 9999
- Runs a final verification pass across all endpoints and prints preflight status
On success you'll see:
━━━ Setup complete ━━━
✓ All services are running.
┌─────────────────────────────────────────────────────┐
│ Dashboard → http://localhost:8888 │
│ DefectDojo → http://localhost:8080 │
│ Neo4j Browser → http://localhost:7474 │
│ Runner API → http://localhost:9999 │
└─────────────────────────────────────────────────────┘
First run takes ~2–3 minutes — DefectDojo runs database migrations on boot. Subsequent runs of
./setup.share fast (services already up, token already set).
./setup.sh --restart # tear down all containers and start clean
./setup.sh --runner # (re)start only the host runner — useful after a rebootCartography maps your AWS account into Neo4j — EC2 instances, S3 buckets, RDS, Lambda, security groups, and their relationships. Run it once before the first pipeline, and again whenever your infrastructure changes.
Before running: enter your AWS credentials via the ⚙ Account Setup panel in the dashboard, then export them into your shell:
export $(grep -v '^#' .env | xargs)
riskenv/bin/cartography \
--neo4j-uri bolt://localhost:7687 \
--neo4j-user neo4j \
--neo4j-password-env-var NEO4J_PASSWORD \
--neo4j-database neo4j \
--aws-best-effort-mode \
--aws-regions "$AWS_DEFAULT_REGION" \
--aws-requested-syncs "s3,ec2:instance,ec2:security_group,rds,lambda_function"The AWS SDK picks up AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY from the environment automatically.
Open http://localhost:8888 and click the ▶ button in the left nav.
Each pipeline card shows a preflight checklist before allowing a run:
AWS Pipeline
- ✓ Prowler installed
- ✓ AWS credentials set (Access Key ID + Secret)
- ✓ AWS region set
- ✓/✗ Prowler AWS scan output exists → click Run Prowler Scan if missing
- ✓ DefectDojo API token set → click Run Pipeline once all checks pass
GitHub Pipeline
- ✓ Prowler installed
- ✓ GitHub token set
- ✓/✗ Prowler GitHub scan output exists → click Run Prowler Scan if missing
- ✓ DefectDojo API token set → click Run Pipeline once all checks pass
Both pipelines stream live logs and step progress in real-time. On completion the dashboard graph and summary auto-refresh.
Pipeline stages (AWS):
[0/6] Clear stale Vulnerability nodes
[1/6] Parse Prowler OCSF JSON
[2/6] Seed findings into DefectDojo
[3/6] Bridge DefectDojo → Neo4j
[4/6] Enrich with CISA KEV + EPSS
[5/6] Score assets (blast-radius graph traversal)
[6/6] Print top-risk assets + IAM coverage report
Pipeline stages (GitHub):
[0/6] Clear stale GitHub Vulnerability nodes
[1/6] Seed GitHubRepository nodes into Neo4j
[2/6] Seed findings into DefectDojo
[3/6] Bridge DefectDojo → Neo4j
[4/6] Enrich with CISA KEV + EPSS
[5/6] Score assets (blast-radius graph traversal)
[6/6] Print results
| Interface | URL | What you'll see |
|---|---|---|
| Custom Dashboard | http://localhost:8888 | Risk summary, attack graph, top risks, IAM blast radius, coverage |
| DefectDojo | http://localhost:8080 | Raw findings per product |
| Neo4j Browser | http://localhost:7474 | Full graph — run Cypher queries directly |
Use the service selector (AWS / GitHub / Azure / GCP pills) at the top of the dashboard to scope all views to a single source.
| Panel | Nav | Description |
|---|---|---|
| Attack Graph | 🕸 | D3 force-directed graph — assets, vulnerabilities, IAM roles, trust edges |
| Top Risks | 🎯 | Ranked findings table with score breakdown (base / exposure / blast / exploit / sensitivity) |
| IAM Blast Radius | 🔑 | AWS roles ranked by Allow policy count |
| Coverage | 📊 | Scan coverage %, blind spots, per-asset scores |
| Run Pipeline | ▶ | Trigger Prowler scans and full pipelines with live log streaming |
| Account Setup | ⚙ | Configure AWS credentials, GitHub token, and DefectDojo token from the browser |
| Synapse Assistant | 💬 | Built-in AI chatbot integrated directly into the dashboard for smart risk querying |
The ⚙ Account Setup panel lets you update credentials from the dashboard without touching the terminal. Values are saved to the runner's .env file and applied immediately — no restart needed.
| Field | Required | Notes |
|---|---|---|
| Access Key ID | ✅ | IAM access key ID |
| Secret Access Key | ✅ | Masked — leave blank to keep existing |
| Session Token | ✗ | Only needed for temporary/STS credentials |
| AWS Account ID | ✅ | 12-digit account ID |
| AWS Region | ✅ | e.g. us-east-1 |
| GitHub Token | ✅ for GitHub | PAT with repo + read:org scopes |
| DefectDojo API Token | ✅ | Obtain from DefectDojo → Admin → API Token |
| Synapse Assistant Key | ✗ | Groq API key to power the AI Chatbot |
Synapse includes a built-in AI chatbot, the Synapse Assistant, accessible as a sleek panel directly within the Dashboard. It serves as your copilot for answering queries about your security posture and risk data.
- Context-Aware: The assistant intelligently filters its answers based on your currently selected data source (AWS, GitHub, etc.) and understands query intents (e.g. data summarization vs. general knowledge).
- Setup: To enable the assistant, supply a valid Groq API key via the
SYNAPSE_ASSISTANT_KEYenvironment variable in.envor configure it interactively from the ⚙ Account Setup menu in the dashboard.
Each asset-vulnerability pair in Neo4j receives a contextual risk score:
score = (base_severity × 0.15) # CVSS → 0–100
+ (exposure × 0.25) # public IP / public S3 ACL / public GitHub repo
+ (blast_radius × 0.25) # reachable data stores or sibling repos
+ (exploitability × 0.20) # EPSS score + CISA KEV membership
+ (sensitivity × 0.15) # prod/pii/secret keywords in asset name
× confidence # 0.7–1.0 based on data completeness
Vulnerability nodes are colour-coded by severity in the attack graph:
- 🔴 Critical (red, largest)
- 🟠 High (orange)
- 🟡 Medium (yellow)
- 🟢 Low (green, smallest)
risk-platform/
├── setup.sh ← full setup & start script (run this first)
├── .env.example
├── .gitignore
├── docker-compose.yml ← Neo4j, DefectDojo, Dashboard
├── demo_infra.sh ← provision intentionally vulnerable AWS resources
├── cartography-config.yaml
│
├── engine/
│ ├── poc_pipeline.py ← AWS pipeline entry point
│ ├── github_pipeline.py ← GitHub pipeline entry point
│ ├── runner.py ← host-side runner API (port 9999)
│ ├── config.py ← all config from env vars
│ ├── import_scans.py ← Prowler AWS OCSF → DefectDojo
│ ├── import_github.py ← Prowler GitHub OCSF → DefectDojo
│ ├── bridge.py ← DefectDojo findings → Neo4j nodes
│ ├── enrichers.py ← CISA KEV + EPSS enrichment
│ ├── risk_engine.py ← blast-radius scoring (AWS + GitHub)
│ ├── init_defectdojo.py ← one-time DefectDojo bootstrap
│ └── requirements.txt
│
└── dashboard/
├── Dockerfile
├── app.py ← Flask API (endpoints + pipeline proxy)
└── static/
└── index.html ← D3.js single-page frontend
All configuration is driven by environment variables. Edit .env (copied from .env.example), or use the ⚙ Account Setup panel in the dashboard.
| Variable | Required | Description |
|---|---|---|
AWS_ACCESS_KEY_ID |
✅ via dashboard | IAM access key ID — enter via ⚙ Account Setup |
AWS_SECRET_ACCESS_KEY |
✅ via dashboard | IAM secret access key — enter via ⚙ Account Setup |
AWS_SESSION_TOKEN |
✗ | Temporary session token (STS / assumed role) |
AWS_ACCOUNT_ID |
✅ via dashboard | 12-digit account ID — enter via ⚙ Account Setup |
AWS_DEFAULT_REGION |
✅ via dashboard | Region to scan (e.g. us-east-1) — enter via ⚙ Account Setup |
DOJO_API_TOKEN |
✅ | Fetched and saved automatically by setup.sh |
GITHUB_TOKEN |
✅ for GitHub | PAT with repo + read:org scopes — set in .env or via ⚙ Account Setup |
NEO4J_PASSWORD |
optional | Default: changeme123 |
DOJO_ADMIN_PASSWORD |
optional | Default: admin |
demo_infra.sh provisions intentionally vulnerable AWS resources to give the platform something interesting to find.
# Ensure AWS credentials are saved via ⚙ Account Setup first, then:
export $(grep -v '^#' .env | xargs)
chmod +x demo_infra.sh
./demo_infra.sh| Resource | Vulnerability introduced |
|---|---|
S3 demo-public-data-<account> |
Public-read ACL, no encryption |
S3 demo-prod-secrets-<account> |
No versioning, no encryption, high-value name |
S3 demo-clean-logs-<account> |
Encrypted + versioned (clean baseline) |
IAM Role demo-overpowered-role |
AdministratorAccess attached |
IAM User demo-nomfa-user |
S3FullAccess, access key, no MFA |
EC2 demo-prod-api-server |
Public IP + open SG (22/3389/3306/80) + overpowered instance profile |
Cleanup: the script prints exact cleanup commands at the end of its run.
| Symptom | Fix |
|---|---|
| Dashboard shows 0 assets | Run Cartography (Step 3) first, then the pipeline (Step 4) |
| Pipeline buttons disabled | Check preflight checklist — a red ✗ indicates what's missing |
| Runner unreachable error | Run ./setup.sh --runner to restart it |
DOJO_API_TOKEN 401 errors |
Run ./setup.sh again — it will re-fetch and save a fresh token |
| DefectDojo 500 on first boot | Wait ~60 s for DB migrations, then re-run ./setup.sh |
| Neo4j connection refused | docker compose up -d neo4j and wait ~15 s |
Prowler AccessDenied |
Ensure the IAM key has read policies for EC2, S3, IAM |
| GitHub scan JSON parse error | Previous scan output was appended — the runner deletes the old file before each new scan automatically |
| Graph has nodes from wrong account | MATCH (n) WHERE n.arn IS NOT NULL AND NOT n.arn CONTAINS ':<ACCOUNT_ID>:' DETACH DELETE n in Neo4j Browser |
| Need a clean slate | Use the 🗑 Reset Database button in the ⚙ Account Setup panel, then re-run Cartography and the pipeline |
| Dashboard stale after code edit | docker cp dashboard/app.py risk-platform-dashboard-1:/app/app.py && docker cp dashboard/static/index.html risk-platform-dashboard-1:/app/static/index.html && docker restart risk-platform-dashboard-1 |