Security and compliance posture
DRAGON is built for environments where session data cannot leave the room: SCIFs, the tactical edge, OT and ICS networks, and classified and air-gapped facilities. The security posture follows from that constraint. This page is the customer-facing statement; the mechanisms behind it are documented in the subsystem references.
The formal threat model is a roadmap deliverable. Until it lands, this page is a posture statement, not an assurance argument. Known gaps are stated plainly below.
No telemetry
DRAGON sends no telemetry by default — no usage analytics, no crash reports, no phone-home. Any future telemetry will be opt-in, documented in full, and forcibly disabled in offline mode.
Offline mode as a provable claim
In offline operation DRAGON makes zero outbound network connections except the device transports the operator explicitly opens. Inference runs on the embedded llama-server child process over loopback, embeddings and the vector store are local, and licensing verifies signed license strings entirely on-device with no entitlement callbacks — the trial itself starts and runs without a network. This is a testable claim, not a marketing one: the audit log's net_egress records are the evidence, capturing every outbound connection the daemon makes.
Air-gapped installs update by installing newer signed installers by hand, verified against the published SHA256SUMS manifest. They never contact the update endpoint.
Two-stage redaction before any model contact
Secrets are scrubbed at two independent stages — at RAG ingestion before text is embedded, and at context assembly before any model call. Coverage spans Cisco type 0, 5, 7, 8, and 9 secrets, enable secret, SNMP communities, TACACS+ and RADIUS keys, IKE PSKs, SSH private-key blocks, password echoes, and a high-entropy heuristic; type 7 is redacted, never decoded. Replacements preserve analytic utility, and every redaction event is logged by class, location, and time, never the secret itself.
A stricter ruleset auto-applies when the inference target is a remote endpoint. The redaction test corpus is its own named CI job, and a redaction escape is a release blocker. See redaction and the audit log.
Auditable AI, with provenance
Every suggestion, acceptance, dismissal, redaction event, model invocation, and RAG retrieval is recorded in an append-only, hash-chained audit log — including the verbatim post-redaction prompt sent on every model call. fs_access and net_egress evidence records tie private-key reads and outbound connections to the originating user action and OS account, an in-product transparency pane sits over the live log, one-click export writes the complete log as canonical JSONL or CSV, and configurable audit storage lets the log be written to a WORM or classified volume, fail-closed. The format is a public artifact, so customers verify and ingest it with their own tooling using only SHA-256.
AI usage honors the license: an expired trial or license stops all model calls — manual, ambient, and auto-analyze — and the network egress and API cost they incur.
Suggested commands are never auto-executed. Acceptance places a command in the input line for the operator to send. No setting overrides this. It is a product invariant, with exactly one narrow, audited exception, below.
The read-only auto-execute gate
Collection Runs are the one place the core transmits commands without a human keypress, and the crossing is deliberately narrow. The executor auto-sends only commands a rules-only classification guard proves read-only — profile rules, then a conservative built-in ruleset, then a reviewed Linux read-only allowlist. Anything else, including any command the classifier does not recognize, is skipped and never transmitted. Every auto-sent and skipped command is written to the audit log as an auto_exec entry with its classification and outcome. The executor is a single choke point — one tested, audited code path rather than execution scattered through the product.
With user-authored sets in v1.3.0, the gate was hardened against smuggled writes: every command a set could auto-run is re-classified at run time; every ingress of user-authored command text rejects in-band control characters (a CR/LF, backspace, Ctrl-U, or ESC that would make the device execute a different command than the one classified), and the executor itself refuses a control-bearing line as a final backstop; and a read-only-classified command carrying redirection, chaining, substitution, or a pipe into anything but a network read-only filter (show > /etc/passwd, ping | tee …) is downgraded and skipped. Snapshot output that enters the copilot's context is redacted, and only output the operator explicitly opted in is ever shown to the model.
Automatic session reconnect is held to the same standard: a background re-dial happens without a keypress, so every attempt and outcome is an audited reconnect entry, bounded by backoff and a give-up window — never an invisible infinite loop.
Credentials
Credentials — session passwords, Vault credentials and key passphrases, and AI API keys — are stored exclusively in the OS keychain (the Windows credential store, macOS Keychain, or Linux Secret Service), never plaintext on disk. The application store keeps only an opaque keychain reference. The wire protocol reports credential presence but never returns a stored secret, private keys referenced by path are read only by the daemon at dial time, and audit payloads carry presence flags, never key material.
An in-app factory reset (Settings → Security & Audit) wipes all DRAGON state on every platform — license, saved sessions, known hosts, Vault credentials, provider keys, RAG index, and audit log. Every secret is destroyed; the only survivor is the trial anti-abuse marker, which holds no secret and no personal data. See licensing.
Local daemon hardening
The core runs as a loopback-bound WebSocket daemon. Because loopback binding alone does not stop a malicious web page via DNS rebinding, the daemon adds layered defenses:
- A loopback-literal
Hostheader requirement and anOriginallow-list, defeating DNS-rebinding and cross-origin drive-by connections. - A per-launch connection token, generated by the shell from the OS CSPRNG on every start and carried as a WebSocket subprotocol so it never appears in a URL, log, or process list. The comparison is constant-time. The token is additive to — never a replacement for — the
HostandOriginchecks. - A concurrent-session cap and per-connection rate limiting on expensive operations, a resource-exhaustion defense.
- RAG ingestion confined to explicitly allowed, symlink-resolved roots and volume-capped per walk, a path-traversal and resource defense.
- Bounded buffers on all untrusted input — capture line and output size, PDF extraction time — so a hostile or malfunctioning device cannot exhaust memory. Dropped internal events are counted and logged, never silent.
These controls were added in response to an internal multi-agent security audit; its findings — one critical, six high, six medium, five low — were all remediated, and each redaction-pattern fix is CI-regression-gated. A separate memory audit drove the RAG ingestion bounds.
Host-key trust
SSH host keys use trust-on-first-use against a strict known_hosts. An unknown host prompts the UI with the SHA-256 fingerprint and a 60-second timeout; a known host presenting a changed key hard-fails as a possible MITM and is not promptable; with no UI to answer, the dial is rejected. Every verdict is audit-logged.
Supply chain and distribution
Every release attaches SBOMs in both SPDX and CycloneDX form covering the Go core, the frontend and shell npm trees, and the Rust shell, plus a SHA256SUMS integrity manifest regenerated over the final artifact set. A release gate verifies artifact completeness before anything publishes. Dependency vulnerability checks run on every build — govulncheck for the Go core and an npm audit posture for the frontend. The core is CGO-free, so cross-compilation needs no per-target C toolchain.
Update signing is mandatory: releases cannot build without the updater signing key, and installs verify every update against the baked-in public key. OS code signing — Windows Authenticode via Azure Trusted Signing and Apple Developer ID with notarization — is wired into the pipeline and activates when the certificates are configured; see the honest-gaps note below.
Known gaps, stated honestly
The posture is documented with its gaps visible:
- The IPC is still loopback TCP, not an OS named pipe or Unix domain socket. The per-launch token mitigates this; the migration remains a tracked hardening item.
- The formal threat model is pending. Assets in scope: credentials, session data, RAG corpora, license keys. Adversaries in scope: endpoint malware, insider exfiltration via remote AI endpoints, supply-chain compromise.
- FIPS-validated crypto is tracked as a roadmap item for federal procurements that require it.
- Audit-log tail-checkpoint signing is a roadmap item; the chain proves integrity and order, not authorship. Custom audit storage onto WORM media is the current mitigation.
- The trial anti-abuse hardening stops casual resets — factory reset, uninstall and reinstall, data-directory deletion, and clock rollback — not a determined adversary. A user who deletes the out-of-data-dir marker itself, forges its integrity tag from the shipped binary, or runs under a second OS account still obtains a fresh trial. A server-issued trial license is the tracked durable fix.
- OS code-signing certificate procurement is in progress. Builds produced without the certificates configured ship unsigned and will trip OS trust prompts such as Windows SmartScreen and macOS Gatekeeper; the updater signature check applies regardless.
Reporting
Send security reports to security@ethrx.io. Customers are encouraged to submit redaction-escape fixtures; fixtures are append-only, so a fixed escape can never regress.
