The latest main branch is supported. Older tagged releases are best-effort.
Do not open a public GitHub issue for security vulnerabilities.
Instead, please report privately via GitHub's private vulnerability reporting on this repository, or by email to the maintainer listed in CODEOWNERS.
Please include:
- A description of the issue and its impact
- Steps to reproduce (PoC if possible)
- Affected versions / commits
- Any suggested mitigation
You can expect an initial response within 72 hours and a remediation plan within 7 days for confirmed issues. We follow coordinated disclosure: please give us reasonable time to fix before public disclosure.
This project applies the following defenses (see docs/SECURITY-HARDENING.md for the full list):
| Layer | Control |
|---|---|
| Source | gitleaks pre-commit hook, secret scanning in CI, signed commits encouraged |
| Dependencies | Dependabot (weekly), pip hashed install in CI, npm audit in CI |
| Code | CodeQL (Python + JS), Bandit, Semgrep |
| Container | Non-root user, read-only root FS, distroless/alpine base, Trivy image scan |
| K8s | NetworkPolicy default-deny, no plaintext secrets in repo, Pod Security Standards: restricted |
| Runtime | Webhook HMAC verification (required, not optional), API-key auth on mutating endpoints, strict CORS allowlist |
| TLS | ALB Ingress with ACM, HSTS via nginx |
The repository ships with safe defaults that refuse to start without explicit configuration. Before running:
- Set
DORA_GITHUB_TOKEN(least-privilege fine-grained PAT, read-only on target repos) - Set
DORA_GITHUB_WEBHOOK_SECRET(≥32 random bytes) — webhook endpoint rejects all requests if unset - Set
DORA_API_KEY— mutating endpoints (/collect/*) return 401 without it - Set
DORA_CORS_ORIGINSto your frontend's exact origin(s);*is rejected at startup - Replace placeholder DB password in
infra/k8s/secrets.yaml.exampleand apply via External Secrets / Secrets Manager — never commit real secrets
| Threat | Mitigation |
|---|---|
| Webhook spoofing | HMAC-SHA256 verification, constant-time comparison, secret required |
| Unauthenticated data ingestion | API key on POST /collect/* |
| Cross-origin abuse | Strict allowlist, no * with credentials, preflight cached |
| Secret leakage in repo | gitleaks pre-commit + CI, .gitignore, External Secrets in K8s |
| Supply chain | Dependabot, hashed pip installs, npm ci, Trivy SBOM scan |
| Container escape | Non-root UID, drop ALL caps, read-only FS, seccomp RuntimeDefault |
| Pod-to-pod lateral movement | NetworkPolicy default-deny + explicit allows |
| Token in image | .dockerignore excludes .env, multi-stage build |
| SQL injection | SQLAlchemy ORM (parameterized), no raw SQL on user input |
| DoS via large payloads | FastAPI request size limits, K8s resource limits |