# AttackTracer Ninja V2 Architecture ## Goal Build a lightweight but robust endpoint agent that: - runs on every monitored Windows device - reads local attack telemetry and optional local vulnerability exports - writes device-level NinjaOne custom fields locally - uploads signed JSON reports to a central n8n ingestion workflow - receives updates through NinjaOne tasks from GitLab-hosted releases This design replaces: - the shared-folder aggregation model - the dedicated `AttackTracerNinjaServer` - organization-level field processing on an endpoint Organization-wide correlation and NinjaOne organization API updates move to n8n. ## Core principles 1. Endpoint collection is local, central correlation is remote. 2. Device custom field writes stay local through NinjaOne-supported endpoint mechanisms. 3. Organization logic never depends on one central Windows server. 4. Update delivery is controlled by NinjaOne, with release artifacts hosted in GitLab. 5. Endpoint uploads are authenticated and tamper-evident. 6. The central pipeline treats endpoint data as useful but never fully trusted. ## Recommended component split ### 1. Endpoint agent Use a compiled Windows agent written in C#. Responsibilities: - scan Windows Security/Application logs - parse supported local logs such as FTP/FileZilla - optionally ingest local exported vulnerability data - build normalized JSON report - print Ninja-style key/value status lines - expose a command for device-local execution from NinjaOne - upload signed report to n8n Why compiled instead of PowerShell-only: - harder to casually tamper with than plain scripts - easier to sign - easier to version and hash-verify - simpler to protect internal protocol logic such as signing and replay prevention ### 2. Thin PowerShell deployment wrapper Use PowerShell only for: - install - uninstall - update - scheduled execution wrapper - NinjaOne field publishing wrapper when needed This keeps operational flexibility while protecting core collection logic inside a signed binary. ### 3. GitLab release channel GitLab hosts: - release ZIP or installer - version manifest - SHA-256 checksum file - optional detached signature Recommended files per release: - `AttackTracerNinjaClient-win-x64.zip` - `version.json` - `AttackTracerNinjaClient-win-x64.zip.sha256` - `release-notes.md` ### 4. n8n ingestion pipeline n8n receives endpoint JSON through an authenticated webhook and performs: - signature validation - timestamp and replay validation - schema validation - persistence to Postgres - organization aggregation - NinjaOne organization field updates - optional notifications ### 5. Postgres as primary store Postgres should be the system of record for incoming reports. Recommended tables: - `devices` - `device_reports` - `device_findings` - `device_vulnerability_findings` - `organization_rollups` - `ingestion_events` ### 6. Optional Nextcloud archive Nextcloud can be used for: - archived JSON bundles - generated HTML reports - long-term human-readable reports Do not use it as the primary operational datastore. ## Endpoint security model ## Threat assumptions Assume an attacker may: - modify files under the install directory - stop scheduled tasks or Ninja jobs - alter local logs - replay older JSON uploads - inspect locally stored configuration Assume an attacker with full local admin or SYSTEM access can eventually subvert the endpoint. The architecture therefore aims to: - raise the effort of tampering - make tampering detectable - reduce blast radius of stolen secrets - preserve central evidence of missing or suspicious reporting ## Required protections ### Signed binaries - Sign the compiled agent executable. - Optionally sign the deployment PowerShell scripts. - The updater must verify Authenticode signature and expected hash before replacing files. ### Protected local secrets Do not embed one global master secret in all clients. Use one of these approaches: - per-tenant ingest token wrapped with DPAPI on each machine - per-device secret provisioned during install and stored encrypted with DPAPI - short-lived signed enrollment flow if you later want stronger provisioning Minimum recommendation: - store an n8n upload secret encrypted via DPAPI in a local config file readable only by SYSTEM/Administrators ### Signed report uploads Each report upload should include: - device identifier - report timestamp in UTC - monotonic nonce or GUID - client version - payload hash - HMAC signature over canonicalized request fields Suggested headers: - `X-ATN-Device` - `X-ATN-Timestamp` - `X-ATN-Nonce` - `X-ATN-Version` - `X-ATN-Signature` n8n must reject: - stale timestamps outside tolerance - duplicate nonce values - invalid HMAC signatures ### Tamper evidence The endpoint should include in its report: - installed client version - scanner execution start/end UTC - whether upload succeeded - hash of produced JSON payload - optional configuration version n8n should track: - expected reporting cadence per device - missing devices - repeated version lag - repeated upload failures - sudden disappearance of formerly noisy devices ### Least-privilege local behavior - install under `C:\Program Files\AttackTracerNinja` - write mutable state under `C:\ProgramData\AttackTracerNinja` - restrict config/log/state ACLs to `SYSTEM` and Administrators - avoid storing writable binaries under user-controlled locations ## Update architecture ## Distribution model NinjaOne remains the deployment engine. Recommended flow: 1. Build signed release in CI. 2. Publish release artifact to GitLab. 3. Publish `version.json` with latest version metadata. 4. NinjaOne scheduled update task runs on endpoints. 5. Update task checks local version against GitLab manifest. 6. If newer, download artifact, verify hash/signature, install, and record result. ## Version manifest Example `version.json`: ```json { "channel": "stable", "version": "2.0.0", "publishedAtUtc": "2026-07-16T18:00:00Z", "artifactUrl": "https://gitlab.example.com/group/project/-/releases/v2.0.0/downloads/AttackTracerNinjaClient-win-x64.zip", "sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "minUpdaterVersion": "1.0.0" } ``` ## Endpoint update task The NinjaOne update task should: - run as SYSTEM - read installed version - fetch `version.json` - compare versions - download ZIP to a temporary directory - verify SHA-256 - verify Authenticode signature on executable - stop running agent if needed - replace files atomically - write update result to a local log The update task should never install unsigned or hash-mismatched artifacts. ## Runtime execution model Recommended commands: - `AttackTracerNinjaCli.exe scan` - `AttackTracerNinjaCli.exe scan --ninja-output` - `AttackTracerNinjaCli.exe upload --report ` - `AttackTracerNinjaCli.exe scan-and-upload` The PowerShell wrapper invoked by NinjaOne should typically run: ```powershell & "C:\Program Files\AttackTracerNinja\app\AttackTracerNinjaCli.exe" scan-and-upload --ninja-output ``` Wrapper responsibilities: - ensure paths exist - capture stdout/stderr to log - set NinjaOne device custom fields from the produced status - return a useful exit code for monitoring ## Suggested data flow 1. Endpoint agent scans local data. 2. Agent writes a JSON report locally. 3. Wrapper publishes device custom fields to NinjaOne. 4. Agent signs and uploads the JSON report to n8n. 5. n8n validates authenticity and freshness. 6. n8n stores raw and normalized data in Postgres. 7. n8n computes organization-level summaries. 8. n8n updates NinjaOne organization fields through the API. 9. Optional HTML and long-form artifacts are generated centrally. ## n8n workflow design ## Workflow A: ingest-device-report Trigger: - Webhook Steps: 1. Validate required headers. 2. Validate timestamp tolerance. 3. Check nonce replay in Postgres. 4. Recompute HMAC and compare. 5. Validate JSON schema. 6. Upsert device metadata. 7. Insert raw report row. 8. Insert findings rows. 9. Mark ingestion success. Failure handling: - log validation error - store rejected attempt metadata - optionally alert on repeated bad signatures ## Workflow B: organization-rollup Trigger: - Cron every 5 or 15 minutes Steps: 1. Query latest accepted report per device. 2. Compute org status and summary. 3. Detect stale devices and missing submissions. 4. Update NinjaOne organization fields: - `attacktracerorgstatus` - `attacktracerorgsummary` - `attacktracerorglastupdate` 5. Optionally generate HTML and archive it ## Workflow C: stale-device-alerting Trigger: - Cron Logic: - find devices with no valid upload within expected interval - raise notification or ticket ## Recommended report contract Each JSON report should include: ```json { "schemaVersion": "2.0", "machineName": "WSUS", "deviceIdHint": "", "organizationHint": "", "generatedAtUtc": "2026-07-16T18:42:11Z", "clientVersion": "2.0.0", "lookbackDays": 7, "baseStatus": "ok", "alertState": "ok", "totalEvents": 0, "uniqueIpCount": 0, "errorCount": 0, "attackFindings": [], "vulnerabilityCorrelation": { "totalCount": 0, "criticalCount": 0, "highCvssCount": 0 }, "runtime": { "startedAtUtc": "2026-07-16T18:42:09Z", "finishedAtUtc": "2026-07-16T18:42:11Z", "uploadAttempted": true } } ``` Authentication metadata should travel in headers, not inside the JSON body. ## Packaging recommendation Use a ZIP-based package for GitLab delivery and NinjaOne installation. Recommended layout: ```text AttackTracerNinjaClient-win-x64.zip app/ AttackTracerNinjaCli.exe AttackTracerNinjaCli.dll scripts/ install-attacktracer-ninja.ps1 uninstall-attacktracer-ninja.ps1 update-attacktracer-ninja.ps1 run-attacktracer-ninja.ps1 config/ attacktracer-settings.example.json VERSION.txt ``` This avoids the operational overhead of a heavy GUI installer while staying easy to deploy from NinjaOne. ## Hardening recommendations - enable script and binary code signing where possible - set strict ACLs on `Program Files` and `ProgramData` content - log every update attempt locally - include a watchdog check for missing executions - keep secrets out of command-line parameters where possible - prefer HTTPS with certificate validation for all uploads - optionally pin the server certificate thumbprint if your environment allows it ## Migration plan ### Phase 1: define v2 contract - freeze current JSON model and derive `schemaVersion 2.0` - define n8n webhook contract - define version manifest format ### Phase 2: build central pipeline - create Postgres schema - create n8n ingest workflow - create n8n rollup workflow - test NinjaOne org field updates from n8n ### Phase 3: refactor endpoint client - remove share mirroring logic - remove organization/server logic from endpoint package - add signed upload path - add DPAPI-backed local secret storage ### Phase 4: implement update channel - publish GitLab release artifacts - implement version manifest check - implement hash/signature validation - implement NinjaOne update task ### Phase 5: controlled rollout - pilot on a small device group - validate upload cadence and rollups - compare with old system - then roll out to all devices ### Phase 6: retire old architecture - stop `AttackTracerNinjaServer` - remove share-based reporting dependency - deprecate old org-report scripts ## Recommendation summary Recommended final direction: - keep a compiled endpoint agent - use PowerShell only as thin install/update/run wrapper - distribute and update through NinjaOne - host signed release artifacts in GitLab - upload signed JSON reports to n8n - store operational data in Postgres - perform organization-level NinjaOne API writes only from n8n This gives the best balance of: - endpoint robustness - easier rollout - central visibility - reduced single-point-of-failure risk - maintainable future growth