Unified Offensive Security Platform — Active/Passive Reconnaissance, DAST, Threat Intelligence, and Breach & Attack Simulation in a single pane of glass.
Built for security teams who need speed. Every scan result, MITRE ATT&CK mapping, CVE correlation, and network asset lands in one dashboard — no external integrations required.
| Service | Role | Port | Technology |
|---|---|---|---|
| nightfall-backend | REST API, scan orchestration, all business logic | 8088 (host) | Go 1.24, Gin, GORM |
| nightfall-frontend | React SPA | 3000 (host) | React 18, TypeScript, Vite, TailwindCSS |
| nightfall-postgres | Primary datastore | internal only | PostgreSQL 16 |
| nightfall-redis | Response cache | internal only | Redis 7 (allkeys-lru, 256 MB) |
| nightfall-zap | DAST sidecar | 8090 (host) | OWASP ZAP stable |
Total: 5 containers. No Elasticsearch, no RabbitMQ, no MinIO, no OpenCTI, no OpenBAS.
- Docker & Docker Compose v2
- 4 GB+ RAM free
- Ports 3000, 8088, 8090 available on the host
git clone https://github.com/shiva0126/nightfall-tsukuyomi.git
cd nightfall-tsukuyomicp .env.example .env # edit values as neededRequired .env variables:
POSTGRES_USER=nightfall
POSTGRES_PASSWORD=changeme
POSTGRES_DB=nightfall
DB_USER=nightfall
DB_PASSWORD=changeme
DB_NAME=nightfall
JWT_SECRET=a-very-long-random-secret-at-least-32-chars
ZAP_API_KEY=nightfall-zap-keydocker compose up -dFirst boot takes ~30 seconds (Postgres init + Go binary startup).
curl http://localhost:8088/health
# → {"message":"Nightfall Tsukuyomi API","status":"ok"}
docker compose exec nightfall-redis redis-cli ping
# → PONGNavigate to http://localhost:3000 and log in.
Default demo account (created on first register):
| Field | Value |
|---|---|
admin@nightfall.local |
|
| Password | (set on first /auth/register) |
| Route | Page | Description |
|---|---|---|
/ |
Dashboard | Risk score, finding trends, scan history, BAS simulation widget |
/scan |
Unified Scan | Launch active/passive scans with auth options; live progress |
/findings |
Findings | All findings with severity, MITRE, OWASP, Kill Chain filters |
/tools |
Tool Workbench | Run individual security tools; ZAP DAST control panel; embedded terminal |
/passive-intel |
Passive Intel | OSINT modules — subdomains, DNS, certs, WHOIS, cloud assets |
/threat-intel |
Threat Intel | MITRE ATT&CK, OWASP Top 10, Kill Chain, CVE Intel tabs |
/breach |
Breach Simulation | OpenBAS-style scenario builder and simulation runner |
/reports |
Reports | Executive, Technical, and Compliance report generation |
/target-dashboard |
Target Dashboard | Per-target deep dive — network map, assets, finding timeline |
/settings |
Settings | API keys, integrations, platform health |
| Mode | Tools | Use Case |
|---|---|---|
safe |
httpx, whatweb, nuclei (safe), sslscan | Light fingerprinting, no intrusive tests |
standard |
+ nmap, nikto, wapiti, fierce | Standard pentest coverage |
aggressive |
+ sqlmap, dalfox, ffuf, gobuster, amass | Full offensive coverage |
ZAP runs as a sidecar container. Two scan modules are available from the Tool Workbench:
| Module | Description |
|---|---|
zap_baseline |
Spider + passive scan — safe for production |
zap_active |
Spider + AJAX spider + passive + active attack |
Auth support: form-based, cookie injection, token/header injection.
110+ OSINT modules including:
- Subfinder, Amass, crt.sh certificate transparency
- DNS brute-force (dnsx, alterx)
- GAU (GetAllURLs), Wayback Machine
- Shodan/Censys/Fofa (via uncover)
- Cloud asset discovery
Pass credentials at scan creation; the scanner handles login flows, cookie extraction, and token injection automatically across all active modules.
On startup (and on demand via POST /api/v1/frameworks/sync), Nightfall pulls the full MITRE ATT&CK Enterprise STIX bundle and seeds OWASP Top 10 + Kill Chain phases. Every finding is automatically enriched with:
mitre_attack_id/mitre_tactic/mitre_techniqueowasp_category/owasp_namekill_chain_phasecorrelation_id(cross-tool deduplication)
All heavy read endpoints are cached in Redis with graceful degradation — the app runs fully without Redis if it's unavailable.
| Endpoint | Cache Key | TTL |
|---|---|---|
GET /frameworks/mitre |
nightfall:mitre:ttps |
2h |
GET /frameworks/owasp |
nightfall:owasp:categories |
2h |
GET /frameworks/kill-chain |
nightfall:killchain:phases |
2h |
GET /findings/stats |
nightfall:findings:stats |
10m |
GET /findings/techstack |
nightfall:techstack:* |
15m |
GET /findings/by-tool |
nightfall:findings:by-tool |
20m |
GET /findings/mitre-matrix |
nightfall:findings:mitre-matrix |
20m |
GET /findings/correlations |
nightfall:findings:correlations |
30m |
GET /mitre/matrix |
nightfall:mitre:full-matrix |
2h |
GET /tools/status |
nightfall:tools:status |
5m |
GET /network-assets |
nightfall:network-assets:* |
10m |
Cache is automatically invalidated when a scan completes or a framework sync runs.
# Inspect live cache keys
docker compose exec nightfall-redis redis-cli keys "nightfall:*"
# Flush all cache (admin endpoint)
curl -X POST http://localhost:8088/api/v1/cache/flush \
-H "Authorization: Bearer <jwt>"
# Cache stats
curl http://localhost:8088/api/v1/cache/status \
-H "Authorization: Bearer <jwt>"All endpoints (except auth) require Authorization: Bearer <jwt>.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/register |
Create account |
| POST | /api/v1/auth/login |
Login → JWT |
| POST | /api/v1/auth/refresh |
Refresh JWT |
| GET | /api/v1/auth/me |
Current user |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/targets |
Create target |
| GET | /api/v1/targets |
List targets |
| GET | /api/v1/targets/:id |
Get target |
| GET | /api/v1/targets/:id/inventory |
Target asset inventory |
| DELETE | /api/v1/targets/:id |
Delete target |
| POST | /api/v1/scans |
Start scan |
| GET | /api/v1/scans |
List scans |
| GET | /api/v1/scans/:id |
Get scan |
| GET | /api/v1/scans/:id/modules |
Live module progress |
| POST | /api/v1/scans/:id/cancel |
Cancel scan |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/findings |
List (filter by scan_id, severity, status, tool_source, target_id) |
| GET | /api/v1/findings/stats |
Severity counts |
| GET | /api/v1/findings/techstack |
Detected tech stack |
| GET | /api/v1/findings/by-tool |
Grouped by tool |
| GET | /api/v1/findings/mitre-matrix |
MITRE heatmap data |
| GET | /api/v1/findings/correlations |
Cross-tool correlated findings |
| PUT | /api/v1/findings/:id |
Update finding (status, assignee) |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/tools/status |
Tool availability + versions |
| POST | /api/v1/tools/execute |
Run a single tool/module |
| POST | /api/v1/tools/scan-all |
Run all tools against a target |
| POST | /api/v1/tools/scan-custom |
Run selected modules |
| GET | /api/v1/tools/executions |
List executions |
| GET | /api/v1/tools/executions/:id |
Execution detail + output |
| POST | /api/v1/tools/executions/:id/stop |
Stop execution |
| POST | /api/v1/tools/terminal |
Raw terminal command |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/zap/status |
ZAP sidecar health |
| POST | /api/v1/zap/scan |
Start ZAP scan |
| GET | /api/v1/zap/scan/:id/status |
Scan progress |
| POST | /api/v1/zap/scan/:id/stop |
Stop scan |
| GET | /api/v1/zap/scan/:id/alerts |
Get alerts |
| GET | /api/v1/zap/scan/:id/report |
Download HTML report |
| GET | /api/v1/zap/scans |
List ZAP scans |
| POST | /api/v1/zap/clear-session |
Reset ZAP session |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/network-assets |
List assets (filter: tenant_id, scan_id) |
| GET | /api/v1/network-assets/:id |
Asset detail + open ports |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/frameworks/status |
Sync status + counts |
| POST | /api/v1/frameworks/sync |
Re-sync MITRE/OWASP/Kill Chain |
| POST | /api/v1/frameworks/remap |
Re-enrich existing findings |
| GET | /api/v1/frameworks/mitre |
All MITRE ATT&CK TTPs |
| GET | /api/v1/frameworks/owasp |
OWASP Top 10 |
| GET | /api/v1/frameworks/kill-chain |
Kill Chain phases |
| GET | /api/v1/mitre/matrix |
Full MITRE matrix (static) |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/cve/mapped |
CVE→finding mappings |
| GET | /api/v1/cve/status |
Last sync run |
| POST | /api/v1/cve/remap |
Trigger CVE re-mapping |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/intel/passive |
Start passive recon |
| GET | /api/v1/intel/passive |
List passive scans |
| GET | /api/v1/intel/passive/:domain |
Results for domain |
| Method | Endpoint | Role | Description |
|---|---|---|---|
| GET | /api/v1/cache/status |
any | Redis info + key count |
| POST | /api/v1/cache/flush |
admin | Flush all cache keys |
| Variable | Default | Description |
|---|---|---|
DB_HOST |
postgres |
PostgreSQL host |
DB_PORT |
5432 |
PostgreSQL port |
DB_USER |
— | Database user |
DB_PASSWORD |
— | Database password |
DB_NAME |
— | Database name |
JWT_SECRET |
required | JWT signing secret (min 32 chars) |
REDIS_HOST |
nightfall-redis |
Redis host |
REDIS_PORT |
6379 |
Redis port |
ZAP_API_KEY |
nightfall-zap-key |
ZAP REST API key |
FRAMEWORK_AUTO_SYNC |
1 |
Sync MITRE/OWASP on startup (0 to disable) |
FRAMEWORK_REMAP_INTERVAL_SECONDS |
30 |
How often to re-enrich unmapped findings |
CVE_INTEL_ENABLE |
1 |
Enable periodic CVE mapping (0 to disable) |
CVE_INTEL_INTERVAL_HOURS |
24 |
CVE sync interval |
SCAN_STALE_MINUTES |
45 |
Timeout before orphaned "running" scans are marked failed |
cd backend
go run cmd/api/main.go
# API on :8080 — connect to local Postgres + Rediscd frontend
npm install
npm run dev
# Dev server on :5173 — proxies /api to :8088# Force re-sync MITRE/OWASP/Kill Chain from upstream
cd backend
go run ./cmd/framework-sync
# Push completed scans to OpenCTI (legacy, optional)
go run ./cmd/export-opencti -limit 20
go run ./cmd/export-opencti -list-connectors| Layer | Technology |
|---|---|
| Backend | Go 1.24, Gin, GORM, PostgreSQL 16 |
| Frontend | React 18, TypeScript, Vite, TailwindCSS, Recharts, Lucide |
| Cache | Redis 7 (go-redis/v9) |
| DAST | OWASP ZAP stable (sidecar) |
| Infrastructure | Docker Compose |
Backend won't start: FATAL: JWT_SECRET environment variable is not set
Add JWT_SECRET to your .env file (minimum 32 characters).
ZAP scans time out or return no alerts
ZAP takes 60+ seconds to fully initialize. Check: docker compose logs nightfall-zap
Redis shows as unavailable in /cache/status
The backend degrades gracefully — all endpoints still work, just without caching. Check: docker compose ps nightfall-redis
Stale scans stuck as "running" after restart
They are automatically marked failed on backend startup after SCAN_STALE_MINUTES (default 45). Set to a lower value if needed.
DB constraint error on target creation (targets_domain_key)
Expected — GORM AutoMigrate sees the existing unique index by its Postgres name. The app handles this correctly.
Authorized Use Only. This platform is for security research, authorized penetration testing, CTF competitions, and educational purposes only. Do not use against systems you do not own or have explicit written permission to test.
Built with Nightfall