12 KiB
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
- Endpoint collection is local, central correlation is remote.
- Device custom field writes stay local through NinjaOne-supported endpoint mechanisms.
- Organization logic never depends on one central Windows server.
- Update delivery is controlled by NinjaOne, with release artifacts hosted in GitLab.
- Endpoint uploads are authenticated and tamper-evident.
- 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.zipversion.jsonAttackTracerNinjaClient-win-x64.zip.sha256release-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:
devicesdevice_reportsdevice_findingsdevice_vulnerability_findingsorganization_rollupsingestion_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-DeviceX-ATN-TimestampX-ATN-NonceX-ATN-VersionX-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
SYSTEMand Administrators - avoid storing writable binaries under user-controlled locations
Update architecture
Distribution model
NinjaOne remains the deployment engine.
Recommended flow:
- Build signed release in CI.
- Publish release artifact to GitLab.
- Publish
version.jsonwith latest version metadata. - NinjaOne scheduled update task runs on endpoints.
- Update task checks local version against GitLab manifest.
- If newer, download artifact, verify hash/signature, install, and record result.
Version manifest
Example version.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 scanAttackTracerNinjaCli.exe scan --ninja-outputAttackTracerNinjaCli.exe upload --report <path>AttackTracerNinjaCli.exe scan-and-upload
The PowerShell wrapper invoked by NinjaOne should typically run:
& "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
- Endpoint agent scans local data.
- Agent writes a JSON report locally.
- Wrapper publishes device custom fields to NinjaOne.
- Agent signs and uploads the JSON report to n8n.
- n8n validates authenticity and freshness.
- n8n stores raw and normalized data in Postgres.
- n8n computes organization-level summaries.
- n8n updates NinjaOne organization fields through the API.
- Optional HTML and long-form artifacts are generated centrally.
n8n workflow design
Workflow A: ingest-device-report
Trigger:
- Webhook
Steps:
- Validate required headers.
- Validate timestamp tolerance.
- Check nonce replay in Postgres.
- Recompute HMAC and compare.
- Validate JSON schema.
- Upsert device metadata.
- Insert raw report row.
- Insert findings rows.
- 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:
- Query latest accepted report per device.
- Compute org status and summary.
- Detect stale devices and missing submissions.
- Update NinjaOne organization fields:
attacktracerorgstatusattacktracerorgsummaryattacktracerorglastupdate
- 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:
{
"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:
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 FilesandProgramDatacontent - 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