Unified AppSec platform — system architecture
Sentinel orchestrates best-of-breed OSS security scanners in sandboxed containers, normalizes
their output into one canonical Finding model (SARIF-2.1.0-inspired), deduplicates across
scanners, and serves a developer-first dashboard. Four runtime processes plus an isolated, untrusted
scanner-execution plane.
System layers & data flow
Each layer hands off to the next; the scanner plane is deliberately isolated from the host.
Browser — Next.js 16 dashboard
Express 5 · REST /v1 · Prisma 7
Persistence & queue
BullMQ worker — orchestrator
Scanner execution plane
--network none|restricted · --read-only · --cap-drop ALL · --no-new-privileges · --pids-limit · --memory · --cpus · --rm · gVisor runsc when available. nmap (NPSL) & masscan (AGPL) run as isolated external-process containers only.The spine — one scan, end to end
The same pipeline runs inline (dev) or via BullMQ (production). Adding a scanner = adding one adapter.
Scanner tools — the orchestrated OSS engines
Each invoked as an isolated container with the verified machine-readable output flag. The demo SCA engine ships default-on; the rest run behind SCANNERS_DOCKER_ENABLED.
| Engine | Type | Target | Output | Network | License |
|---|---|---|---|---|---|
| Trivy 0.71.2 | SCA | repo / image | --format sarif | none | Apache-2.0 |
| OSV-Scanner 2.4.0 | SCA | lockfiles | --format json | none | Apache-2.0 |
| Semgrep 1.167 | SAST | source repo | --sarif | none | LGPL-2.1 |
| gitleaks 8.30.1 | SECRET | git history | --report-format sarif | none | MIT |
| checkov 3.3 | IaC | IaC files | -o sarif | none | Apache-2.0 |
| OWASP ZAP 2.17 | DAST | live URL | -J report.json | restricted | Apache-2.0 |
| Nuclei 3.9.0 | DAST | live URL | -jsonl | restricted | MIT |
| nmap 7.99 | PORT | host / IP | -oX (→ JSON) | restricted | NPSL · isolated |
| masscan 1.3.2 | PORT | IP ranges | -oJ | restricted | AGPL-3.0 · isolated |
Monorepo packages
Three apps + four shared packages. ESM JavaScript on Node 22 (backend) · TypeScript (web).
Data model
● org-scoped tables carry orgId and are reached only via withOrgScope. Spine: User → Org → Project → Target → Scan → Finding.
Architectural invariants (§9 · machine-checked)
Each rule has a invariants.json entry the lint runner enforces in CI and at the drift gate. 11 machine-checkable · 2 manual.
withOrgScope; no direct ORM on scoped tables.assertResourceAccess.unique(orgId, fingerprint), not app logic.ownershipVerified=false.Stack & cross-cutting concerns
Tier: small (<1k concurrent). HTTPS only · multi-tenant · structured JSON logs · Sentry · daily Postgres snapshots.