| ID | Control Name | NIST CSF 2.0 | ISO 27001:2022 | Owner | Evidence | Verified | Notes |
| CTL-001 | Geo-disambiguation filter | ID.RA, DE | A.8.7 | Backend Eng. | AMBIGUOUS_COUNTRY_NAMES + isGeoRelevant() in 3 paths | Current | |
| CTL-002 | Topic relevance scoring | ID.RA | A.8.11 | Backend Eng. | topicScore() at ingest, /africa/events, /social-search | Current | |
| CTL-003 | JWT authentication | PR.AA | A.5.15 | Security Lead | requireAuth middleware, revocation table | Current | |
| CTL-004 | Role-based access control | PR.AA | A.8.2 | Security Lead | requireRole() middleware, ROLE_LEVELS hierarchy (admin/analyst/field/observer/free) | Current | |
| CTL-005 | MFA for login | PR.AA | A.5.17 | Backend Eng. | mfa_codes table, nodemailer/Brevo SMTP delivery | Current | |
| CTL-006 | Rate limiting | PR.PT | A.8.6 | Security Lead | RATE_LIMIT_RULES per route in security-middleware.js | Current | |
| CTL-007 | CSP / security headers | PR.PS | A.8.20 | Security Lead | attachSecurityMiddleware(), nonce-based CSP, HSTS, X-Frame-Options | Current | |
| CTL-008 | Audit logging | DE.CM | A.8.15 | DevOps/SRE | audit_log table, writeAudit() on all admin actions | Current | |
| CTL-009 | Prompt injection sanitisation | PR.DS | A.8.7 | Backend Eng. | sanitizePromptInput() — blocklist + token stripping in security-middleware.js | Current | |
| CTL-010 | Webhook HMAC signing | PR.DS | A.8.24 | Backend Eng. | WEBHOOK_SIGNING_KEY env var, sha256 HMAC on all outbound webhook payloads | Current | |
| CTL-011 | Startup dependency check | PR.PS | A.8.9 | DevOps/SRE | REQUIRED_MODULES check at boot — process.exit(1) with clear message on missing module | Current | |
| CTL-012 | Confidence scoring model | ID.RA | A.8.11 | Data/Intel Lead | computeConfidence() per event — freshness, corroboration, source quality. UI badge on each feed item. | Current | |
| CTL-013 | Error handler ordering | PR.PS | A.8.28 | Backend Eng. | attachErrorHandler() exported separately, called after all routes are registered | Current | |
| CTL-014 | Health endpoint | DE.CM | A.8.16 | DevOps/SRE | GET /health — public, returns uptime, node version, API key presence | Current | |
| CTL-015 | False-positive telemetry | DE.CM | A.8.16 | Data/Intel Lead | dropped_geo/topic counters per /social-search request; hourly aggregation in search_metrics table; GET /admin/metrics | Current | |
| CTL-016 | Route authorization tests | PR.AA, GV.OV | A.5.15 | Engineering Lead | route-auth-tests.js + GitHub Actions workflow (route-auth-tests.yml) — runs on every push to master, tests all /admin/* routes across all roles | Current | |
| CTL-017 | Backup and restore | RC | A.8.13 | DevOps/SRE | backup.sh (SQLite .backup + integrity check + compress, 14-day retention) — cron runs daily at 02:00 UTC on production server; logs to /var/log/africa-watch-backup.log | Current | |
| CTL-018 | CI/CD security gates | PR.PS | A.8.29 | Engineering Lead | npm audit (--audit-level=high) + CodeQL SAST + TruffleHog secret scan in GitHub Actions (security.yml); deploy blocked until security-gate job passes | Current | |