Continuous Adversary is my summer-internship project: a continuous adversary-emulation and security-validation platform. It answers a question most vulnerability scanners can only guess at — "Is this CVE in our software actually exploitable on our systems, and would our monitoring catch it if someone tried?" — and it answers it safely, without ever touching production or exposing proprietary source code to the internet.
It is a defensive-security research project built end-to-end during the internship, with a formal design report, a working validated baseline, and a hardened, auditable architecture.
The problem it solves
Continuous vulnerability assessment joins two facts that are usually managed separately:
- Public intelligence describes which software versions are affected by a given advisory.
- Local inventory describes what an organization actually runs.
A scanner correlates the two and produces a list: "package v is affected by advisory c." But that match is only a hypothesis. It does not tell you whether the vulnerable code path is reachable in your deployment, whether the exploit really works against your exact build, or — most importantly for a blue team — whether your detections would fire if it were exploited.
Turning that hypothesis into a verified, evidence-backed answer normally means one of two bad options: run untrusted exploit code against production, or copy proprietary application source onto some internet-facing testing box. Both are unacceptable. Continuous Adversary's whole design exists to close that gap without either risk.
Architecture
Two isolated network segments sit either side of the Kali control host. The asset segment holds the real Windows target; the attack segment holds the disposable sandbox and the SIEM. The target and the sandbox have no route to each other — code only ever runs where it is safe to run.

What it does, end to end
Continuous Adversary runs a strict, auditable lifecycle. Every step below is a control, not just a stage:
- Inventory (outbound-only agent). A Windows agent runs as a scheduled
SYSTEMtask and pushes an authenticated software inventory to the control host every 15 minutes. The target opens every connection; the control host never connects inbound and never supplies a filesystem path. This shrinks the target's attack surface to almost nothing. - Deterministic matching. Installed package versions are matched to advisories through OSV (exact ecosystem/name/version), and standalone products against local NVD/CPE data. Exact dependency matches become candidates; fuzzy product matches stay flagged as "needs review."
- Human approval gate. Nothing proprietary moves automatically. A transfer requires an explicit, expiring campaign approved by two distinct people — the service owner and a security approver.
- Safe source transfer. Once approved, the agent gets a freshly generated key pair that expires within five minutes, scrubs configuration and secrets out of the bundle, and uploads it over restricted SFTP. The control host quarantines, hashes, and validates the bundle without executing it.
- Disposable sandbox. A worker restores a clean Windows Server "golden snapshot," rebuilds the exact vulnerable service inside it, and validates the finding there — never on the real asset.
- Detection validation. When the optional Wazuh integration is enabled, Continuous Adversary correlates the bounded test window against
wazuh-alerts-*through a dedicated read-only account — so you learn not just "is it exploitable" but "did the SOC see it." - Guaranteed cleanup. The sandbox snapshot is restored again in a
finallypath — after success, failure, and not-exploitable runs alike. Nothing persists between tests.
Why the design is the point
This is a defense-in-depth, zero-trust system, and the security is in the invariants, not the features:
| Design decision | Why it matters |
|---|---|
| Outbound-only agent protocol | The protected machine exposes no inbound management service — the single biggest reduction in attack surface. |
| Two isolated networks, no route between target and sandbox | The real asset and the place code actually runs can never reach each other. |
| Two-person, time-boxed approval | No single operator (or compromised account) can exfiltrate source or launch a test. |
| Short-lived Ed25519 keys + strict host-key checking | A leaked credential is worthless minutes later; every identity is pinned. |
| Fail-closed leases and re-validation before every job | Policy, dependency evidence, expiry, and freshness are all re-checked at the last moment. |
| Read-only, authenticated dashboard | Operational visibility that cannot approve a bundle or start a test — separation of duties enforced in the UI. |
| Snapshot-restore isolation | Every run starts from a known-clean state and leaves nothing behind. |
The internship also produced a formal control-plane specification (FastAPI, PostgreSQL, OpenID Connect, React/TypeScript, hardened Docker Compose) that replaces the manual commissioning bridge with an auditable, identity-backed campaign workflow — with signed, replay-resistant connector commands and staged rollout — while keeping all source and raw inventory local to the control host.
The operator's view
The dashboard is authenticated and strictly read-only. It gives the SOC full visibility — queue depth, the test running right now, verified findings, and alerts needing attention — but by design it cannot approve a bundle or launch a test. That separation of duties is enforced in the UI itself.

The inventory view is where public advisories meet local reality: each running service on the target is listed with its ecosystem, exact dependency count, dependency-scan status, and whether it has an automatic sandbox adapter — i.e. whether Continuous Adversary can reproduce and validate it safely.

Why it's a strong project
- It closes a real gap. Most tooling stops at "you might be vulnerable." Continuous Adversary proves or disproves it with evidence, and folds detection validation into the same loop — that's genuine purple-team value.
- Safety is engineered, not assumed. Network isolation, two-person control, expiring credentials, fail-closed leases, and guaranteed teardown are the core of the design.
- It's a complete system. A Windows agent, a CVE-intelligence pipeline, an orchestrator, a disposable-sandbox lifecycle, a SIEM correlation layer, and a read-only dashboard — designed, built, documented, and validated end to end.
- It's honest about scope. The report cleanly separates the validated baseline from proposed work and states its non-goals, which is exactly how serious security engineering is written up.
🛠️ Stack & Techniques
- Agent & orchestration: Python, PowerShell, scheduled
SYSTEMtasks, systemd services - Transport security: OpenSSH forced commands, restricted authorized keys, Ed25519, short-lived authorization, strict host-key checking
- Vulnerability intelligence: OSV API (version-exact package queries), NVD/CPE correlation, CISA KEV enrichment, deduplication and ranking
- Isolation: VirtualBox golden snapshots, dual-homed control host with IP forwarding disabled, air-gapped target/sandbox networks
- Detection validation: Wazuh alert correlation over a read-only Indexer account
- Proposed control plane: FastAPI, PostgreSQL, OpenID Connect, React/TypeScript, hardened Docker Compose
- Deliverables: formal design report, protocol specification, and offline + integration tests