Security & Compliance Whitepaper
Everything a CISO, security engineer, or IT decision-maker needs to evaluate ET Ducky for deployment in enterprise and managed-service environments.
Executive Summary
ET Ducky is a cross-platform endpoint monitoring and behavioral-security platform with first-class agent support for Windows and Linux. The Windows agent uses Event Tracing for Windows (ETW); the Linux agent uses eBPF programs attached to scheduler and syscall tracepoints. Both feed identical event shapes into the same correlation pipeline and the same AI-powered root cause analysis, providing deep visibility into system health, performance, and security events. The platform is designed for SMBs and Managed Service Providers (MSPs) as an alternative to full-stack RMM solutions. Every architectural property described in this document applies to both operating systems unless explicitly noted.
Per-Agent Bearer Tokens
256-bit cryptographic tokens with SHA-256 hashed server-side storage. No shared secrets.
Zero-Trust Multi-Tenancy
Complete organization isolation via Clerk-managed identities and row-level data separation.
TLS Everywhere
All agent-to-cloud, user-to-API, and WebSocket communications enforced over TLS 1.2+.
Behavioral Security Monitoring
An always-on ETW behavioral monitor on Windows detects encryption sweeps, shadow-copy deletion, and backup sabotage with automatic host isolation on high-confidence detections. A cross-platform rule engine on both Windows and Linux watches the kernel-event stream for suspicious exec chains, mass file access, reverse-shell heuristics, non-interactive privilege escalation, and unusual outbound traffic.
Least-Privilege Linux Agent
The Linux agent runs as the unprivileged etducky user under a hardened systemd unit. Privileged actions follow an operator-driven elevation model: each sudo command requires an operator password at the moment of the action, captured in an immutable audit row.
This document covers the platform's security architecture, authentication model, data handling practices, infrastructure hardening, and compliance posture. It is intended to provide the technical detail required for security review and organizational approval.
Architecture Overview
ET Ducky operates as a three-tier SaaS platform consisting of a cross-platform agent (Windows and Linux), a cloud API, and a web-based management dashboard.
Windows Agent
.NET 10 Windows Service running as LocalSystem. Collects ETW events and health metrics. Ships data to cloud API over HTTPS.
Linux Agent
.NET 10 systemd unit running as the unprivileged etducky user with hardened sandbox settings. Collects eBPF kernel events, /proc and /sys metrics, and SMART data. Same wire format and authentication as the Windows agent.
Cloud API
ASP.NET Core 10 application running in Docker on DigitalOcean. Handles agent registration, data ingestion, real-time communications, and AI analysis.
Web Dashboard
React SPA served via static hosting. Communicates exclusively with the Cloud API. Clerk-authenticated.
Database
DigitalOcean Managed PostgreSQL with TimescaleDB extension for time-series telemetry data. Encrypted at rest.
Data Flow
Data Flow Summary
Agent → Cloud API: Health metrics (CPU, memory, disk, network), ETW events, heartbeats. All POST/GET over HTTPS with bearer token authentication.
Cloud API → Agent: Configuration updates, ETW collection commands, shell/file/query session requests. Delivered via Server-Sent Events (SSE) over HTTPS.
Dashboard → Cloud API: User actions (view data, manage agents, configure alerts). Authenticated via Clerk JWT tokens over HTTPS.
Cloud API → Anthropic: Telemetry summaries sent for AI analysis. No PII or credentials included. See AI Integration section.
Authentication & Access Control
Agent Authentication
Agents authenticate to the cloud API using per-agent bearer tokens, a system designed to eliminate shared secrets and ensure each agent has a unique, revocable credential.
| Property | Detail |
|---|---|
| Token Format | Opaque prefixed string with 32 random bytes (256-bit entropy) |
| Generation | Server-side via RandomNumberGenerator.GetBytes(32) (CSPRNG) |
| Server Storage | Only the SHA-256 hash is stored in the database. Plaintext is never persisted server-side. |
| Agent Storage | Bearer token stored in the agent configuration under C:\ProgramData\ETDucky\Agent\AgentConfig.json. On disk it is persisted as a DPAPI-encrypted value bound to the local machine account; the plaintext token is held only in memory after decryption. NTFS ACLs restrict file read access to SYSTEM and local Administrators. |
| Issuance | Returned once during agent registration. Never retrievable again. |
| Transport | Authorization: Bearer <token> header on all HTTPS requests and WebSocket upgrade requests. WebSocket URLs never include the token as a query parameter. |
| Validation | Server hashes incoming token with SHA-256, performs database lookup against stored hash, resolves agent identity. |
| Revocation | Revoke via the admin dashboard or API. Invalidation takes effect immediately on the next request — no grace period or cached sessions. |
Registration Token Flow (Initial Onboarding)
New agents are onboarded using short-lived registration tokens created by organization administrators in the dashboard. These are distinct from bearer tokens:
- Registration tokens are AES-256-GCM encrypted, may have expiration dates and max-use limits, and are used only during the initial
POST /api/agents/register-with-tokencall. - Upon successful registration, the server issues a permanent bearer token to the agent and the registration token is consumed.
- Registration tokens can be revoked at any time via the dashboard.
User Authentication (Dashboard)
User authentication is handled entirely by Clerk, a third-party identity provider. ET Ducky does not store passwords, manage sessions, or handle MFA directly.
| Feature | Implementation |
|---|---|
| Identity Provider | Clerk (clerk.com) — SOC 2 Type II certified |
| Authentication | JWT tokens issued by Clerk, validated server-side on every API request |
| MFA Support | Configurable via Clerk dashboard (TOTP, SMS, passkeys) |
| Session Management | Managed by Clerk; configurable session lifetime and idle timeout |
| SSO | Clerk supports SAML and OIDC enterprise SSO (available on Clerk Enterprise plan) |
| Webhook Verification | All Clerk webhooks verified via HMAC-SHA256 signature (svix-signature header) |
Multi-Tenancy & Role-Based Access
ET Ducky is a multi-tenant platform with a two-level isolation model and defense-in-depth at both the application and database layers.
Workspaces (subdomains) and organizations
- Workspace — the outer isolation boundary, materialized as a subdomain on
etducky.com(e.g.acme.etducky.com). The terms “workspace” and “subdomain” refer to the same entity from the user-facing and infrastructure-facing perspectives respectively; the database column isSubdomainIdand the user-facing label is “Workspace.” Workspaces are auto-provisioned at sign-up with a random readable slug (e.g.etd-x7q3p2) and can be renamed by their owner from Settings → Workspace. Renames are FK'd bySubdomainId, not slug, so every binding (org membership, agent registration, integration config) is preserved; the previous slug remains active as a grace-period alias for a configurable window so in-flight bookmarks, invite links, and agent SSE connections continue to function during the cutover. The*.etducky.comwildcard certificate is centrally managed; customers do not configure DNS or TLS for the default URL. - Clerk Organizations — the inner isolation boundary. One workspace can host multiple Clerk organizations (typical for MSPs managing several client tenants). Agents, events, alerts, scripts, tickets, and integrations are scoped per Clerk organization within a shared workspace. The dashboard's organization picker switches the active scope; the URL stays the same.
- Custom domains — optionally, a customer can map their own domain (e.g.
app.acme.com) to their workspace. Verification is via DNS TXT record; certificates are issued automatically from Let's Encrypt and renewed on a 90-day rotation.
Workspace membership cascade
To prevent inconsistencies between “the user belongs to my workspace” and “the user can actually see anything in it,” ET Ducky enforces a server-side membership cascade between the two layers:
- User joins a workspace — the
WorkspaceMembershipFanoutServiceadds the user to every Clerk organization that already lives in the workspace. The fan-out is invoked from the workspace invite acceptance path, the Clerk webhook handler for org membership creation, and the org-binding admin endpoint, so every code path that creates a workspace membership ends in the same fan-out. - New organization is created in the workspace — all existing workspace members are added as members of the new organization. This means an MSP onboarding a new client doesn't have to re-invite each of their own analysts to the new client org.
- User is removed from a workspace — the cascade reverses, removing them from every Clerk organization in the workspace. A user cannot retain access to organizations in a workspace they no longer belong to.
Per-organization invites at the organization's URL (rather than at the workspace URL) bypass the cascade by design: this is the path used for granting client-only access (e.g. a customer's IT contact who should see their own organization but not other clients in the MSP's workspace).
Cross-workspace enumeration safety
A user can be a member of multiple workspaces. To prevent organization names or membership lists from one workspace leaking into another's UI, every organization picker in the dashboard sources its options from a single server-side endpoint, GET /api/organizations/in-current-subdomain, which returns the organizations belonging to the workspace identified by the request's host header.
- Server is the source of truth. The dashboard does not enumerate organizations from the user's Clerk session (which holds memberships across all workspaces). All dropdown options come from the workspace-scoped endpoint.
- RLS bypass is explicit and bounded. The endpoint runs inside
RootTenantContext.UseAsyncfor the lookup of organizations bound to the current subdomain — necessary because the Organizations RLS policy is scoped to the active organization, not the active workspace. The result set is then re-filtered against the workspace'sSubdomainIdin code before being returned. - Active-org recovery. If the dashboard detects that the user's Clerk-active organization is not in the current workspace's org list (a common case after switching workspaces), it intersects the user's Clerk memberships with the workspace org list, calls
Clerk.setActive()with a valid org, and reloads — rather than letting the user issue requests that would 403 against the workspace.
Database-layer isolation
- PostgreSQL Row-Level Security (RLS) — every tenant-scoped table has a policy of the form
bypass_rls = 'on' OR Id = app_current_org(). Per-request GUCs (app.bypass_rls,app.current_org,app.current_subdomain) are emitted by an EF Core command interceptor before every database command. Policies are enforced by the database itself, independent of application code — a query that omits the tenant filter or runs with the wrong context returns zero rows. - Application-layer filters — EF Core
HasQueryFilterapplies on the same tenant-scoped entities as a second line of defense. A query that escapes EF's filter is still rejected by the database's RLS policy. - Bypass scopes are explicit — only background services, webhook handlers, and bootstrap auth lookups (e.g. validating an agent bearer token before tenant context is set) run inside
RootTenantContext.UseAsync. These call sites are static-analyzed by an in-tree Roslyn analyzer that flags any DbSet read missing a documented bypass justification.
Subscription & quota
- User-scoped licenses (Option B) — a Clerk user holds a single License row carrying their tier and Stripe subscription metadata. Subscriptions and seats follow the user across whatever organizations they belong to.
- Org-pooled quotas at runtime — AI query quota for an organization is the sum of its members' active license quotas. This makes seat-stacking work for teams (your members' subscriptions add up) without coupling subscription ownership to a specific tenant.
What we do NOT do
- No global admin view across customers. Anthropic / ET Ducky staff have no in-product way to see one customer's data while logged in. Admin endpoints are restricted to localhost on the API server (no exposed paths) and gated by an additional shared secret.
- No SQL access path that bypasses RLS by accident. The interceptor emits
bypass_rls='off'by default; explicit opt-in viaRootTenantContextis required. Misconfigured PgBouncer (transaction pooling instead of session pooling) would break GUC propagation, so we run PgBouncer in session-pool mode and the connection string explicitly points at the session-mode listener.
Encryption
| Layer | Standard | Detail |
|---|---|---|
| In Transit | TLS 1.2+ | All agent→API, dashboard→API, and WebSocket connections enforced over HTTPS/WSS. TLS is terminated at Cloudflare's edge (DDoS + WAF); the origin connection from Cloudflare to the DigitalOcean load balancer is re-encrypted, and the load balancer terminates that second hop with managed certificates. |
| At Rest (Database) | AES-256 | DigitalOcean Managed PostgreSQL encrypts all data at rest. Automated daily backups are also encrypted. |
| Registration Tokens | AES-256-GCM | Registration tokens are encrypted with AES-256-GCM before storage. The encryption key is managed as an environment variable, never in source code. |
| Bearer Tokens | SHA-256 | Only SHA-256 hashes are stored server-side. Plaintext tokens exist only in agent config files and in memory during validation. |
| File Integrity | SHA-256 | File hashes for agent update packages and uploaded files computed using SHA-256. For installers, the hash of the signed binary is anchored in the version manifest at build time and re-verified server-side on every download (see Update & Installer Integrity). |
| Agent Installer | AES-256-GCM | Self-extracting installer packages use AES-256-GCM encryption with a .NET launcher stub for secure deployment. |
Data Collection Scope
ET Ducky collects system telemetry plus limited connection metadata — the source IP an agent connects from, used for security and abuse prevention. The platform is not designed to and does not collect end-user personal content, browsing history, keystrokes, file contents, or employee activity.
What Is Collected
- Health Metrics: CPU utilization, memory usage, disk space, network I/O, uptime
- ETW Events: Windows kernel and user-mode trace events (process creation, file I/O, network connections, registry activity, service state changes) — configurable per-agent. During AI-driven dynamic diagnostic sessions (see Dynamic ETW Diagnostic Sessions), additional providers may be enabled on a per-investigation basis; events from those providers are counted on the host and the counts-only summary is uploaded — raw event payloads from diagnostic sessions never leave the endpoint.
- System Identity: Hostname, OS version, agent version, and the source IP address the agent connects from — recorded at registration and refreshed on each check-in (the agent's most recent connection IP; the originating client IP is used when the agent is behind a proxy or CDN). Used for security monitoring, abuse prevention, and incident investigation.
- Event Log Summaries: Recent error counts from Windows Event Log (configurable lookback window)
- Endpoint hardware fingerprint: A stable device fingerprint (machine/MAC/disk identifiers, plus timezone and locale) that lets us recognize the same physical machine across agent re-installs and across accounts — including an actor's own staging machines — even when a fresh agent identifier is generated each time.
- Invalid-credential beacons: Connections presenting revoked or unknown agent credentials are recorded (agent ID, source IP, first/last seen, count) so still-active or compromised endpoints can be identified after an account is terminated.
- Observed indicators: Domains, URLs, and IPs appearing in evaluated commands are extracted into our indicator store to detect and block reuse of attacker infrastructure across the platform.
- Fraud & abuse signals: A non-reversible payment-card fingerprint and account sign-up context are retained to detect a single operator spinning up multiple accounts. A cross-account match flags the account for review and preserves its evidence; it does not by itself restrict the account — tenant isolation and the command filter already contain what a flagged account can do.
What Is NOT Collected
- User credentials, passwords, or authentication tokens from monitored systems
- File contents, email content, or application-layer data
- Keystrokes, screen captures, or user behavior tracking
- End-user Personal Identifiable Information beyond machine/device identifiers used for security
- Full payment card numbers, CVV, or expiry (only a non-reversible fingerprint is stored)
- Browser history, cookies, or session data
Data Retention
ET Ducky offers configurable per-agent data retention with automatic purging enforced by a background service.
| Tier | Retention Period | Price | Purge Method |
|---|---|---|---|
| Default | 14 days | $0 | Automatic background service |
| Extended | 90 days | $0.50/agent/month | Automatic background service |
| Annual | 365 days | $1.50/agent/month | Automatic background service |
| Maximum | 730 days | $2.50/agent/month | Automatic background service |
Data purging runs as a scheduled background task that deletes telemetry older than the configured retention window. Purged data is permanently deleted from the database; no archival copies are maintained unless configured by the customer at the infrastructure level.
Data Residency
All ET Ducky infrastructure is currently hosted in DigitalOcean's US regions. Data does not leave the United States for storage or processing, with one exception: AI analysis requests are sent to Anthropic's API (see AI Integration).
Distribution Servers (LAN File Hubs)
Distribution Servers let an organization nominate an agent as a LAN-local file hub that serves a mountable WebDAV/HTTPS share to other machines on its network. The design enforces a strict control-plane / data-plane split: the cloud governs access and holds the catalog, while file contents move directly between the requesting client and the hub on the customer's own infrastructure.
Control Plane vs. Data Plane
- Control plane (cloud): connection definitions, access-control rules, the file catalog (relative path, size, SHA-256), audit records, and short-lived signed grants. The cloud never stores or proxies file contents.
- Data plane (hub agent): file bytes live in a content-addressable, SHA-256-deduplicated cache on the hub's own disk and are served over the hub's own TLS listener directly to LAN (and, when enabled, WAN) clients.
Access Control & Mount Credentials
- Per-path ACLs: each connection carries rules granting
list/read/write/deleteto a principal — everyone-in-org, an organization role, or a specific user (IdP-group principals are planned) — on a path prefix or filename glob. The most-specific matching rule wins. - Live evaluation: ACLs are resolved at credential-validation time, not frozen into the credential. Grants, revocations, and permission changes reach existing mounts within the hub's short validation-cache window without re-issuing or remapping anything.
- Opaque mount keys: WebDAV clients authenticate with a mount key — a key id plus a 256-bit CSPRNG secret presented over HTTP Basic. The secret is stored only as a per-row salted SHA-256 hash, is shown once at issuance, and is never retrievable again. Keys are scoped to their grant, optionally expiring, and revocable.
- Hub-bound, cloud-validated: the hub validates each presented key against the cloud rather than trusting a self-contained offline token. A key is therefore honored only by the hub it was issued for, and revocation takes effect within the validation-cache window rather than waiting for an expiry.
Data Residency
Because the cloud acts solely as the control plane, the contents of a Distribution Server never traverse the ET Ducky cloud. File bytes stay within the customer's own infrastructure, on the network path between the requesting client and the hub. This holds for both LAN and WAN access — WAN reach changes only how a client discovers and connects to the hub, not where the data flows.
Transport & Certificate Trust
- TLS only: the hub serves exclusively over HTTPS. Agent-to-hub transfers additionally pin the hub's certificate fingerprint, which the cloud distributes alongside the signed grant.
- Non-agent devices: the hub's self-signed certificate is trusted once per device. The dashboard provides a private, authenticated certificate download for signed-in members. An optional public download link — off by default, unguessable, admin-created, and revocable — covers devices without a dashboard login. Only the certificate's public part is ever exposed by that link; the mount secret, the actual credential, is never part of it.
WAN Reachability (Customer-Side Only)
Off-LAN access is opt-in per hub and uses only customer-side reachability. The hub classifies its NAT type and discovers its public address via STUN, may request a router port-mapping (UPnP/NAT-PMP), and accepts an admin-configured manual port-forward. There is no ET Ducky-operated relay in the path: if no customer-side route is reachable, the connection fails explicitly rather than falling back through vendor infrastructure, preserving the data-residency guarantee end to end.
Hosting & Infrastructure
| Component | Provider | Detail |
|---|---|---|
| Application Server | DigitalOcean Droplet | Docker containerized ASP.NET Core 10 application |
| Database | DigitalOcean Managed PostgreSQL | TimescaleDB extension, encrypted at rest, automated backups, private VPC networking |
| DNS / CDN | Cloudflare | DDoS protection, TLS termination, WAF rules |
| Frontend Hosting | Static / CDN | React SPA served via Cloudflare-proxied static hosting |
| Container Runtime | Docker Compose | Single-container deployment with health checks and restart policies |
Network Security
- AllowedHosts: API configured to only accept requests with
Host: etducky.comheader, preventing host header injection attacks. - CORS Policy: Strictly limited to
https://etducky.com. No localhost or wildcard origins permitted in production. - Database Access: PostgreSQL accessible only via DigitalOcean's private VPC network and trusted IP sources. No public internet exposure.
- SSH Access: Hardened SSH configuration with key-only authentication and password login disabled.
- Docker Networking: API container ports bound to localhost only; external traffic routed through reverse proxy with TLS.
- Admin Endpoints: Administrative API endpoints restricted to localhost-only access (127.0.0.1/::1), not reachable from the internet.
Secrets Management
All sensitive credentials are managed via environment variables injected at runtime through Docker Compose and .env files with restricted permissions (chmod 600). No secrets are stored in application configuration files, source code, or container images. Migration to Docker Secrets (file-based injection via /run/secrets/) is planned to eliminate secrets from process environment visibility.
| Secret | Purpose | Rotation |
|---|---|---|
| PostgreSQL credentials | Database authentication | Rotatable via DigitalOcean dashboard |
| Clerk API keys | User identity management | Rotatable via Clerk dashboard |
| Stripe API keys | Billing / subscriptions | Rollable via Stripe dashboard |
| Anthropic API key | AI analysis engine | Rotatable via Anthropic console |
| SendGrid API key | Transactional email | Rotatable via SendGrid dashboard |
| SSL.com eSigner credentials | EV code signing (installer signing) | Rotatable via SSL.com dashboard; TOTP secret regenerated on rotation |
| AES-256 encryption key | Registration token encryption | Rotatable (invalidates active registration tokens only) |
| Admin secret | Localhost-only admin API access | Rotatable via openssl rand |
Agent Installation & Deployment
Windows Agent
The Windows agent is deployed as a Windows Service installable via a self-extracting installer or MSI package.
| Property | Detail |
|---|---|
| Runtime | .NET 10 (self-contained, no external runtime required) |
| Service Account | LocalSystem, required for ETW kernel-level trace access |
| Installation Path | C:\Program Files\ETDucky\ |
| Data Path | C:\ProgramData\ETDucky\Agent\ |
| Silent Install | Supported via /S flag for mass deployment (SCCM/Intune compatible) |
| Installer Security | AES-256-GCM encrypted self-extracting archive with .NET launcher stub |
| Auto-Update | Agent checks for updates every 6 hours. From 2.4.0.3, downloaded installers must pass SHA-256 verification against the manifest-anchored hash plus Authenticode validation with a pinned signer before install — see Update & Installer Integrity |
| At-Rest Token Protection | The bearer token in AgentConfig.json is wrapped with DPAPI bound to the LocalSystem account, so a copy of the file off-host is useless. |
Linux Agent
The Linux agent is deployed as a systemd unit via .deb, .rpm, or universal .run packages, or via the install.sh one-liner enrollment flow.
| Property | Detail |
|---|---|
| Runtime | .NET 10 (self-contained, no external runtime required) |
| Service Account | Unprivileged etducky:etducky user. Privileged operations route through the operator elevation flow described below. |
| Capture Backend | libbpf-based eBPF programs attached to scheduler and syscall tracepoints (sched_process_exec, sys_enter_openat, sys_enter_connect, sys_exit_accept4). CO-RE relocations with BTFHub fallback. Requires kernel 5.4 or later; earlier kernels run in a graceful no-op mode that still ships health metrics. |
| journald Capture opt-in | Optional reader that tails journalctl --output=json --follow and emits each entry as a normalised SystemEvent on the same pipeline as eBPF. Surfaces failed service starts, OOM kills, sudo/su sessions, SSH login chains, kernel WARN_ON dumps. Default priority floor is warning; throttled to 1000 lines/minute with a synthetic marker emitted when lines are dropped so downstream consumers can detect signal loss. Cursor (__CURSOR) is persisted to /var/lib/etducky/journald.cursor so restarts don't replay history. Disabled by default. |
| auditd Capture opt-in | Optional reader that polls ausearch --raw --start checkpoint --interpret on a 30-second cadence (kernel-side cursor — no manual state file). Surfaces file-watch hits, capability use (CAP_SYS_ADMIN etc.), SELinux/AppArmor AVC denials, USER_LOGIN/USER_END records. The systemd unit grants AmbientCapabilities=CAP_AUDIT_READ so ausearch works without root; the optional auditctl rule install needs CAP_AUDIT_CONTROL. Disabled by default; on hosts without auditd the reader logs a single warning and exits cleanly. |
| Installation Path | /opt/etducky/agent/ |
| Data Path | /var/lib/etducky/ (mode 0750, owned by etducky) |
| Config Path | /etc/etducky/agent/AgentConfig.json (mode 0600, owned by etducky). Agent refuses to start if the config file has weaker permissions. |
| systemd Hardening | ProtectSystem=strict, ProtectHome=read-only, PrivateTmp=yes, ProtectKernelTunables=yes, ProtectControlGroups=yes, RestrictNamespaces=yes. Capability bounding set is restricted to what eBPF and operator-elevated commands require. |
| Resource Bounds | MemoryMax=512M, CPUQuota=50%, TasksMax=256. A runaway agent process cannot starve the host. |
| Silent Install | Supported via install.sh with environment variables for unattended enrollment. |
| Auto-Update | Agent polls the API on the heartbeat cadence and self-installs verified packages via apt/dnf or the universal extractor. |
Operator-Driven Privilege Elevation (Linux)
The Linux agent does not run with standing root authority. When an AI live session generates a privileged command (sudo apt install, sudo systemctl ..., etc.), the agent does not execute it directly. Instead, it posts an elevation request to the cloud API; the dashboard pops a modal for the responsible operator with the command summary; the operator types the host's sudo password; the cloud API forwards the password to the agent over the same authenticated SSE channel that delivers commands; and the agent runs the command via sudo -S with the password fed in over stdin. Each elevation produces an immutable audit row capturing:
- The Clerk user id of the authenticating operator
- The source IP and user agent of the dashboard request
- The command summary and the full command text
- The full lifecycle timestamps (pending, granted, executed, completed)
- Exit code and any error summary
Passwords are never stored. They cross the wire as part of the SSE grant payload encrypted in transit, are zeroed in agent memory after use, and never appear in any log. A narrowed /etc/sudoers.d/etducky-rmm drop-in grants NOPASSWD only for read-only diagnostics (smartctl, dmidecode, lshw, journalctl, dmesg) and the systemctl restart etducky-agent self-management command. Everything else routes through the operator-elevation flow.
The result is that compromise of the agent does not equal compromise of root. An attacker who pivots into the etducky service account can exfiltrate the agent's bearer token (which only authenticates to one specific organization on the cloud API) but cannot run privileged commands without convincing a real operator to type a password into the dashboard.
Agent Resource Footprint
The agent is designed for minimal system impact:
- Health-Only Mode (default): Collects only system health metrics (CPU, memory, disk, network) with negligible overhead. ETW event tracing is disabled by default and enabled on-demand from the dashboard.
- Bandwidth Optimization: A correlation engine aggregates and summarizes ETW events before transmission, achieving approximately 99.95% bandwidth reduction compared to raw event forwarding.
- Memory Optimization: On-demand ETW collection control reduces memory usage by approximately 98.9% when ETW is not actively needed.
- Local Buffering: Events are buffered in a local SQLite database (
events.db) to survive network interruptions. Buffer is capped at a configurable max size (default: 10,000 events) with automatic cleanup. - Configurable Intervals: Collection and transmission intervals are tunable (default: 60 seconds each).
Agent Communications
Communication Channels
- HTTPS REST API — Registration, heartbeats, data upload, configuration polling. All requests use
Authorization: Bearerheader. - Server-Sent Events (SSE) — Real-time command channel from server to agent. Agent maintains persistent HTTPS connection. Used for ETW start/stop commands, configuration pushes, script execution, session requests, and isolation management (
agent.unisolatefor remote network isolation lift). All dispatched commands are risk-scored and logged before delivery. Commands that include configuration JSON are filtered on both the server and agent to strip protected keys (e.g., bearer tokens, API endpoint, agent ID) before persistence. - WebSocket (WSS) — Used only for remote desktop relay sessions. Authenticated via
Authorization: Bearerheader during the WebSocket upgrade; tokens are never transmitted in the URL or query string. Sessions are ephemeral and initiated only by authenticated dashboard users.
The agent never opens inbound ports or listens for incoming connections. All communication is initiated outbound by the agent to https://etducky.com.
TLS Certificate Pinning: The agent validates the server's TLS certificate against a set of SPKI SHA-256 pin hashes compiled into the binary, in addition to standard OS certificate chain validation. This prevents MITM attacks even if a rogue certificate authority is trusted at the OS level. A two-slot rolling pin rotation is supported: the server pushes a "next" pin via the heartbeat response so pins can be rotated without an agent update.
File transfer path policy (agent-enforced)
Bidirectional file transfers between the dashboard and the agent are constrained by a hardcoded path allow-list inside the agent itself, not negotiated server-side:
- Push (dashboard → agent): the agent always writes pushed files to
C:\ProgramData\ETDucky\Agent\Downloads\<filename>. ThedestinationPathfield in the API request is intentionally ignored on the agent side — a comment inFileTransferService.csdocuments this: "server-provided destinationPath is intentionally ignored to prevent arbitrary writes." A compromised dashboard or stolen Clerk session cannot land files in arbitrary locations on the agent host. - Pull (agent → dashboard): source paths must resolve to a location under
C:\ProgramData\ETDucky\Agent\. Anything else is rejected with the literal string "Source path not allowed by agent policy." The agent treats the dashboard request as an untrusted hint and applies its own allow-list before opening any file. - Chunk integrity: all transfers happen in 1 MB chunks. Chunks are transmitted as base64 over HTTPS, with SHA-256 file-level integrity verification once reassembly completes.
The effect is that the agent treats the dashboard as a directing authority, not a trusted commander. Even if our cloud were fully compromised, the agent cannot be coerced into reading or writing outside its own data directory.
Behavioral Security Monitoring
ET Ducky's behavioral security layer has two parts. On Windows, an always-on ETW behavioral monitor runs a dedicated kernel session and triggers automatic network isolation on high-confidence detections (described first below). On both Windows and Linux, a cross-platform rule engine subscribes to the same kernel-event stream the diagnostic pipeline uses and fires named-rule detections that surface in the dashboard with the actual triggering events attached as evidence (described second).
Windows ETW Security Monitor
The Windows agent runs a dedicated ETW kernel session (ETDucky_Security) entirely independent of the on-demand diagnostic session. The monitor observes a narrow slice of system activity, file renames, process spawning, and registry writes, and feeds it through four specialized detectors. No events are ever persisted to disk by this subsystem; data is evaluated in-memory and discarded.
| Detector | What It Watches | Confidence Model |
|---|---|---|
| File Encryption Tracker | Per-process file rename rate with extension changes within a rolling 30-second window (default threshold: 20 renames). Recognises ~40 known ransomware extensions (.locked, .ryuk, .lockbit, .wncry, etc.). | Critical if ≥50% renames match known extensions; High if all renames converge on a single unknown extension; Medium otherwise. |
| Shadow Copy Deletion | Process command lines matching vssadmin delete shadows, wmic shadowcopy delete, bcdedit /set recoveryenabled No, wbadmin delete catalog/backup, and PowerShell-wrapped variants. | Always Critical — these commands have no routine administrative purpose. |
| Backup Sabotage | sc.exe / net.exe / PowerShell commands that stop or disable VSS, Windows Backup, or common third-party backup agents (Veeam, Acronis, Backup Exec). Also watches for direct registry writes that set backup service start type to Disabled (value 4). | Always Critical. |
| Process Ancestry | Suspicious parent→child spawn chains: Office apps, browsers, PDF readers, and script hosts spawning cmd.exe, PowerShell, certutil, bitsadmin, regsvr32, rundll32, schtasks, etc. | High if child launched from a staging path (\temp\, \appdata\, \public\, etc.); Medium otherwise. |
A per-detection-type cooldown (default: 60 seconds) suppresses alert floods during a single attack burst. Each alert includes a human-readable evidence summary and full raw evidence in the ticket body.
Automatic Network Isolation
When a detection meets or exceeds the configured minimum confidence (default: High), the agent automatically applies network isolation by setting the Windows Firewall default outbound action to Block across every profile (Domain, Private, Public) and adding explicit Allow rules prefixed ETDucky-Isolation-. The combined effect is that all outbound traffic is denied except:
- The ET Ducky agent process — a
program=allow rule on the agent executable so the agent keeps reaching the cloud regardless of cloud-side IP rotation - The ET Ducky API endpoint (
etducky.com) — a backup IP-based allow rule using addresses resolved at isolation time - DNS resolution — UDP/TCP port 53 from the Windows DNS Client service (
svchost.exe), required because hostname resolution on Windows happens in a separate process from the calling agent - Loopback (127.0.0.0/8). IPv6 loopback is permitted implicitly by Windows Firewall's default loopback handling.
- Operator-configured vendor allowlist (CrowdStrike, SentinelOne, Microsoft Defender for Endpoint, etc.) via
SecurityMonitoring.IsolationAllowedHosts
Isolation is idempotent. The agent persists its isolation state to %ProgramData%\ETDucky\isolation.state on every transition; on startup it reconciles persisted state against rules-on-disk so legitimate isolation survives reboots, accidental leftovers from a crashed prior run are cleaned up, and a stuck default-block with no rules is restored to the operator's pre-isolation outbound policy. A ticket is submitted to the organisation's connected ticketing system with the full alert details, including a note that isolation was applied.
Why profile-default-block rather than an explicit Block-Outbound rule. Windows Firewall evaluates rules in the order [authenticated bypass → block → allow → default action]. A block rule with program=Any wins against any allow rule regardless of specificity, so the seemingly natural "block everything, allow the agent" pattern can never let the agent through. Setting the profile-level default to Block and relying on Allow rules to punch through is the Microsoft-documented quarantine pattern and the only model that lets specific-program allows function correctly.
Hardening: Restricted Operations While Isolated
When an agent is in any non-normal isolation state (isolating, isolated, or unisolating), the cloud refuses admin-initiated commands that could be used to bypass the dual-party lift flow. This is the primary defense against a compromised dashboard admin account using ET Ducky's legitimate command surface to push system-level activity onto a quarantined endpoint. The agent itself also refuses the same set of events (defense-in-depth) when NetworkIsolationService.IsIsolated == true.
Blocked while isolated: shell command execution (interactive sessions and ad-hoc), script execution (single-agent and multi-agent — isolated targets skipped from a fleet run with a per-agent error), live troubleshooting sessions (single and multi-agent), live-session query submission, remote desktop sessions, file push to agent, file pull from agent, ETW collection start (collection stop remains allowed for cleanup), configuration push, remote agent restart, configuration reset to defaults, and agent uninstall.
Still allowed: heartbeats and reporting, isolation lift commands themselves (the dual-party flow), session/transfer cleanup operations, isolation-state reads by the dashboard. The agent remains visible, reachable, and recoverable; only the system-level command surfaces a compromised admin would need to undermine isolation are gated.
Isolation Lift
Isolation removal uses a dual-approval model: an authenticated request from the dashboard is necessary but not sufficient — a user physically present at the device must independently approve the request before firewall rules come down. This design ensures that a compromised dashboard account, stolen session cookie, or malicious insider with valid credentials cannot silently de-isolate a device. The on-device operator is always notified and must consent.
Two paths satisfy the dual-approval requirement:
- Local lift (HMAC-TOTP code): an org admin generates a one-time code in the dashboard and a user with physical access to the device enters it in
LiftIsolationForm. The code is HMAC-TOTP-signed against a hash of the agent's bearer token, valid within a 10-minute TOTP window (the agent accepts the current window ± 1, giving up to ~20 minutes of effective validity to absorb clock skew), single-use, and verified entirely on-device. Possession of either factor alone does nothing — the dashboard can't lift without the user, and the user can't lift without a freshly-issued code. - Remote lift (dashboard-initiated, on-device approval): an authenticated dashboard operator pushes an
agent.unisolatecommand via the SSE channel. The agent generates a single-use nonce, spawnsUnisolateApprovalFormin the active console session via session-0 cross-session launch, and waits up to 5 minutes for the user to click Approve. Only after explicit on-device approval does the firewall rule come down. If no console session exists, the form fails to launch, the user clicks Deny, or the 5-minute timer expires — the lift is denied and the host stays isolated.
Every lift event — approved, denied, or timed out — is recorded in the per-tenant audit log with the requesting dashboard user, the on-device approver (if any), timestamp, and source IP, so security teams can reconstruct any incident's full chain of authorization.
Three paths exist depending on the device state:
- Remote lift with device approval (primary path): An authenticated administrator sends an
agent.unisolatecommand via the SSE channel. The agent spawns an approval dialog on the active interactive desktop (the logged-in user's visible screen) usingWTSQueryUserToken+CreateProcessAsUserto cross the Session 0 isolation boundary. The dialog displays a security alert, a 5-minute countdown, and ET Ducky support contact details. The user must explicitly click Approve; closing the window or timeout auto-denies. Only on approval does the agent remove allETDucky-Isolation-*firewall rules. - No interactive session (permanent rejection): If no user is logged in when the command arrives, the agent permanently rejects the request. It reports back to the cloud via
POST /api/agents/{id}/isolation/unisolate-rejected, which broadcasts anagent.unisolate.rejectedSSE alert to all org dashboard connections. The only resolution is to delete the agent from the org dashboard and re-install it after physical access to the device is restored. - Local lift code (offline endpoints): If the endpoint cannot reach
etducky.com, a technician physically present at the machine can enter a one-time code generated from the dashboard. The code is an 8-character Crockford Base32 string derived as follows:
Lift Code Algorithm
window = unix_time() / 600 # 10-minute TOTP-style window
key = SHA-256(bearer_token) # server stores this; agent derives it at runtime
data = "etducky-isolation-lift-v1:{window}"
hmac = HMAC-SHA256(key=key, data=data)
code = CrockfordBase32(hmac)[0:8]
- Key derivation: The HMAC key is
SHA-256(bearer_token), not the raw token. The server stores only this hash (BearerTokenHash) and uses it directly; the agent hashes the plaintext it holds in memory. Neither side ever transmits or stores the raw token beyond the initial registration response. - The agent accepts codes from the current window ± 1 window (up to ~20-minute effective validity) to absorb clock skew.
- Each code is single-use: the agent records accepted codes and rejects replays.
- Constant-time comparison is used to prevent timing-based oracle attacks.
- The Crockford Base32 alphabet (no I, L, O, U) reduces transcription errors.
Isolation Threat Model
The isolation feature is designed against a specific set of threats with explicit defenses, and explicitly acknowledges one residual gap that no endpoint security product can fully close. The honest disclosure here helps customers reason about what the feature can and cannot do.
| Threat | Can lift isolation locally? | Can mark agent as normal cloud-side? |
|---|---|---|
| Compromised dashboard admin only (phished session, stolen cookie, malicious insider with valid credentials) | No — requires on-device user consent | No |
| Compromised local Windows user (non-SYSTEM) | No — cloud must initiate the lift | No |
| Compromised local Windows SYSTEM / Administrator on the host | Yes — can directly modify Windows Firewall rules and profile defaults via netsh / Set-NetFirewallProfile |
No — cloud state still reflects "isolated" until an authenticated lift POST arrives; the discrepancy is visible to operators |
| Both compromised cloud admin + compromised on-device user (intended dual-party path) | Yes — this is the legitimate lift flow by design | Yes |
The local-SYSTEM row is the residual gap that no Windows-based endpoint security tool can fully close: an attacker who has already escalated to SYSTEM owns the firewall stack and can disable any rule it wants. ET Ducky's design property is that the cloud-side state cannot be modified by a local SYSTEM attacker — isolation status in the dashboard remains accurate even if local enforcement has been bypassed. An operator reviewing the dashboard against ground truth on the host will see the discrepancy. This is consistent with the security model of every comparable product (CrowdStrike, SentinelOne, Microsoft Defender for Endpoint, etc.) — once SYSTEM is conceded, local controls are advisory; only the cloud's record of isolation status is authoritative.
The hardening described in §Restricted Operations While Isolated additionally ensures that even a compromised dashboard admin cannot use ET Ducky's command surface (shell, scripts, sessions, remote desktop, file transfer, config push, uninstall) to drive a compromised-SYSTEM-on-host into a "both factors compromised" state without independent consent from the on-device user.
Kill Switch
The security monitor can be disabled entirely by setting SecurityMonitoring.Enabled = false in AgentConfig.json. This is a graceful kill switch that stops the ETW session without requiring an agent restart. The setting is also configurable remotely via the standard config.change SSE command.
Cross-Platform Rule Engine
In addition to the Windows-specific ETW security monitor, the agent runs a cross-platform behavioral rule engine that subscribes to the same kernel-event stream the diagnostic pipeline uses (ETW on Windows, eBPF on Linux). Rules are defined once and fire on either operating system from a single definition. Five rules ship today:
| Rule | What It Watches | Default Severity |
|---|---|---|
| Suspicious Exec Chain | A shell process executes a network downloader (curl, wget, certutil, bitsadmin), and the downloader's PID then spawns another shell within 30 seconds. The canonical pattern for piped-to-shell attacks. | High |
| Mass File Access | A single process touches 200+ distinct paths in 5 seconds, and the paths span at least 3 user-data root directories. Tuned to fire on commodity ransomware behaviour without flagging legitimate sweeps that stay within one tree. | High |
| Reverse-Shell Heuristic | A shell binary executes within 10 seconds of a network event on the same process tree. Heuristic by design; legitimate session daemons (sshd accepting and spawning bash) trigger the same pattern, so the rule's evidence panel includes the network endpoint so operators can verify. | High |
| Privilege Escalation From Non-Interactive Parent | sudo, pkexec, su, doas, or runas spawned from a parent that is not on the interactive-shell allowlist (bash/sh/zsh, sshd, login, terminal multiplexers). Suggests escalation in a daemon, cron job, or exploit context rather than a human shell. | Medium |
| Unusual Outbound From System Daemon | A whitelisted system daemon (sshd, chronyd, systemd-resolved, postgres) initiates an outbound connection to a port that is not on its expected list. Suggests credential-stuffing C2, exfiltration to a non-standard port, or a misconfigured upstream. | Medium |
Each detection is persisted to the per-organization AgentBehavioralDetections table with the rule id, severity, the process the rule pinned the match to, and the actual triggering events as evidence (capped at 10 entries per detection). Detections push to the org's dashboard within seconds of observation via Server-Sent Events. Acknowledgement is operator-attributed and idempotent. Rules are versioned with the agent today; database-backed rule definitions with hot-update are on the near-term roadmap.
The cross-platform rule engine and the Windows ETW security monitor coexist. The ETW monitor's automatic network isolation on encryption sweeps and shadow-copy deletion remains the highest-confidence Windows-only response; the cross-platform rules surface earlier-stage indicators before automatic isolation criteria are met.
Per-Process False-Positive Suppression
Several legitimate workloads pattern-match against the behavioral rules: AI coding assistants legitimately read many files for context analysis (trips Mass File Access); backup agents do the same; some build systems use curl | sh as an install bootstrap (trips Suspicious Exec Chain). To suppress these without disabling the rule for any other process, organization admins maintain a Behavioral Detection Allowlist — a per-organization list of (process name, rule id) tuples. The list is edited on the Integrations page and exposed at /api/organizations/{clerkOrgId}/behavioral-allowlist.
Enforcement happens server-side before a detection is persisted: the cloud API loads the allowlist into a hash set keyed by (process, rule), scans incoming detections, and drops matches. Suppressed counts are logged but never stored, so an attacker cannot use the allowlist UI to mask an attack and then have the suppression itself be audit evidence. Agents fetch their organization's copy from /api/agents/me/behavioral-allowlist at startup and on configuration polls; future agent versions self-filter so the suppressed bytes never leave the host.
Exemptions are scoped per-rule. Allowing claude.exe on Mass File Access does not exempt it from Suspicious Exec Chain or any other rule. Only organization admins can edit the list; member-role users can read it (so unprivileged agent fetches and dashboard reads still work). The recommendation is to keep entries narrow — broad exemptions weaken the protection model.
Data Minimisation & Event Upload Policy
ET Ducky agents do not continuously stream raw kernel events to the cloud. By default, only the following crosses the wire:
- Aggregate health metrics (CPU, memory, disk, network, hardware health) on the heartbeat cadence (default 60 seconds).
- Inflection-bracketed evidence: when a metric anomaly fires, the agent attaches the kernel events from the surrounding window so the cloud can show "what was happening when CPU spiked" without rejoining against an event store.
- Behavioral detections: each rule firing carries its hand-picked triggering events, capped at 10 per detection, as evidence.
Raw kernel events stay on the endpoint. They are kept in a bounded local buffer that ages out under a configurable retention policy (default 60 seconds for the in-process working set, longer for the on-disk SQLite buffer if events would have shipped but the network was down).
When an operator opens a live session or issues an explicit collection command from the dashboard, a reference-counted upload gate opens for the duration of that work. While the gate is open, the full kernel-event stream from that agent ships to the cloud. When the operator closes the session or the collection command's window expires, the gate closes and the agent returns to minimised upload mode. The result is that quiet hosts transmit very little; hosts under investigation transmit the full stream the operator asked for, and only those.
An on-agent significance filter further curates what flows even while the gate is open: shared library loads, locale catalog opens, /proc reads from system daemons, and other high-volume noise are dropped or deduplicated locally. This applies on both operating systems and means that "we have eBPF/ETW running" does not translate to "we ship 10k+ events per heartbeat" the way an unfiltered firehose would.
Dynamic ETW Diagnostic Sessions
When an operator opens a guided troubleshooting session, ET Ducky now runs an AI-driven diagnostic ETW session alongside the always-on baseline. Instead of either capturing the full firehose or asking the operator to pick providers manually, the AI picks the ETW providers for each round of the investigation, observes what arrives, and decides which providers to enable next. The architecture is the substantive product differentiator: nobody else (that we're aware of) is orchestrating the ETW session layer with an AI in the loop.
The investigation also runs shell commands, not just ETW. For information- and task-shaped requests (“I need my IP info”, “restart the spooler”) the AI begins with the appropriate command rather than an ETW round — kernel ETW (Process/Thread) cannot see host or network configuration, so command-first both answers faster and avoids dead-ends. ETW is then used as verification — confirming a process is actually running, or that traffic is occurring — when it adds signal. Commands are OS-aware (PowerShell on Windows, shell on Linux), selected from the agent's reported OS.
Command execution preserves the “no unauthorised actions” guarantee. Only read-only diagnostics auto-run, so the loop can read a result and pick the next step without a click. That set is gated by a conservative allow-list (for example ipconfig / Get-Net* on Windows, ip addr / systemctl status on Linux) plus a deny-list that blocks statement chaining, redirection, and any state-changing verb; anything not provably read-only is refused auto-run. Every command — auto-run or not — is still risk-scored and written to ShellCommandSecurityLogs. Any state-changing command pauses for explicit technician approval (approve, edit, or skip) before it runs, and AI-proposed fixes continue through the Process Automations approval gate described below.
Two-Session Isolation
The diagnostic session is a separate TraceEventSession pair with a unique per-investigation name — never the baseline ETDucky_Kernel / ETDucky_User sessions. A bug or misconfiguration on the diagnostic side cannot drop, mute, or modify always-on telemetry. The two sessions share no state and tear down independently.
Each investigation creates its own engine instance on the agent. The AI plans a round at a time: it sees the host's tier-filtered provider catalog (Tier 1 well-known plus Tier 2 recently-active, roughly 200 providers out of the 1,500–2,500 the typical Windows host registers), the currently-enabled providers, the most recent evidence snapshot (counts only — see below), and the engine's remaining budget headroom. It returns a structured plan: which providers to enable, which to disable, how long to capture before the next round. The loop applies, captures for the bounded window, snapshots, and re-plans, until the AI concludes or the round cap fires (default 5, hard ceiling 10).
Raw events from diagnostic sessions stay on the host. The engine counts events into a per-(provider, event id, task, opcode) tally; only that counts-only summary travels back to the cloud. Tear-down at the end of the investigation purges the diagnostic session's event buffers and disposes both underlying TraceEventSession objects. The data-stays-local invariant the agent has always held for baseline telemetry continues to hold for AI-driven dynamic diagnostics: the conclusion travels (which providers fired, how often, what the AI concluded); the evidence stays on the endpoint.
One narrow addition to the round-summary payload: alongside the counts-only breakdown, the agent ships any pre-classified verdicts emitted by a local rule engine that runs against the round's events before tear-down. Each verdict is a fixed-vocabulary record — severity, a known rule identifier (e.g., AadConditionalAccess, TlsUntrustedRoot, KerberosSpnUnknown), the rule's pre-authored explanation text, and a pre-authored suggestion. No raw event payloads, file paths, IP addresses, hostnames, or process identifiers are included in the verdict. The rule engine reads the events; the verdict carries only the verdict. The local in-session sample the rules consulted (bounded at 1,000 events) is discarded with the rest of the diagnostic session's raw buffers in the tear-down step, so the data-stays-local invariant is preserved: derived findings travel, raw evidence does not.
The dashboard does not expose a manual provider picker for the diagnostic session. The live-session UX stays AI-orchestrated end-to-end — the operator describes the issue in natural language, the AI handles provider selection. Operators who want to think about ETW providers directly reach for the standalone ETDucky Provider Explorer (the OSS sister tool), not the production dashboard.
Engine-Enforced Budget Caps
The AI is constrained by the engine, not trusted to behave. Per-investigation budget caps are enforced inside the dynamic capture engine itself; the AI cannot bypass them, override them, or negotiate around them. A request that would exceed a cap is refused at the API boundary with a structured error the AI must re-plan around.
| Cap | Default | Enforcement Point |
|---|---|---|
| Concurrent providers per session | 16 | Admission check on EnableProviderAsync |
| Aggregate events/sec per session | 25,000/s | Admission check (projection) + rolling-window watchdog |
| Aggregate events/sec across all diagnostic sessions on the host | 50,000/s | Process-global accumulator; admission + watchdog |
| In-flight buffer memory per session | 64 MiB | Admission check |
| Hypothesis-loop rounds per investigation | 5 default / 10 hard ceiling | Loop guard — runaway loops self-terminate inside two minutes at defaults |
| Per-round capture window | 10–120 seconds | Loop guard |
When in-flight throughput exceeds a session cap (the cost catalog's estimate was wrong, or the host is busier than projected), the engine triggers emergency scale-back: the most-recently-enabled provider is automatically disabled and a structured event is raised so the AI can re-plan rather than retry blindly. Concurrent investigations per host are also capped (default 4) and any diagnostic session that goes 15 minutes without a command from the cloud is reaped by an on-agent sweeper, so a cloud orchestrator that loses track of an investigation cannot leave engines pinned indefinitely.
Remediation Script Handoff
When an investigation concludes with a known-fix pattern, the AI generates a remediation script (PowerShell on Windows, Bash on Linux) that is pushed through the existing Process Automations approval gate — the same org-admin review flow that protects recorder-generated scripts. The script row is created with ApprovalStatus = "pending_review" and an associated review ticket is filed in the org's ticketing system; no remediation runs until an organization administrator approves.
Two execution modes:
- Live guided-troubleshooting session, operator attending: the script is created with
auto_run_eligible = true. After approval, the operator can run it immediately in-session through the existing Process Automations execution path (which itself enforces command security policy). - Background / scheduled / dashboard-initiated investigation, no operator: the script is created with
auto_run_eligible = falseand stays as analysis-only. A human picks it up, reviews, and decides whether to run.
The product claim that ET Ducky does not take unauthorised actions on customer hosts remains intact: the approval gate, the per-command security policy, and the org-admin role-check apply equally to AI-generated remediation scripts and to scripts written by humans. AI-generated remediations are tagged with Origin = "process_automation" and a CreatedBy = "dynamic-etw:<jobId>" marker so the audit trail makes the source unambiguous.
AI Integration Security
ET Ducky uses Anthropic's Claude API for AI-powered root cause analysis, natural language querying, and smart reporting.
| Concern | Implementation |
|---|---|
| Data Sent to AI | Aggregated telemetry summaries only: CPU/memory trends, event correlation summaries, error patterns. No PII, credentials, file contents, or raw user data. |
| AI Provider | Anthropic (anthropic.com) — does not train on API data per their commercial terms. |
| Data Retention by AI | Anthropic API does not retain prompt/response data beyond the request lifecycle per their data policy. |
| Network Path | Server-side only. AI requests originate from the cloud API, never from the agent or browser. |
| Opt-Out | AI analysis features are user-initiated (not automatic). No telemetry is sent to AI providers unless a user explicitly triggers an analysis. |
| Sensitive Data Filtering | Prompts are constructed server-side with allowlisted query types. Raw database queries are parameterized and validated against an allowlist-based QueryEngine. |
Third-Party Service Dependencies
| Service | Purpose | Data Shared | Compliance |
|---|---|---|---|
| Clerk | User authentication & identity | Email, name, org membership | SOC 2 Type II |
| Stripe | Payment processing | Billing email, subscription status | PCI DSS Level 1 |
| Anthropic | AI analysis engine | Aggregated telemetry summaries | SOC 2 Type II |
| SendGrid | Transactional email (alerts) | Recipient email, alert content | SOC 2 Type II |
| DigitalOcean | Infrastructure hosting | All platform data | SOC 2 Type II, ISO 27001 |
| Cloudflare | DNS, CDN, DDoS protection | HTTP traffic metadata | SOC 2 Type II, ISO 27001 |
Supply Chain & Dependencies
- Agent (Windows): .NET 10 self-contained build with no runtime dependencies on the target system. Package dependencies sourced from NuGet with deterministic builds.
- Agent (Linux): .NET 10 self-contained build packaged as
.deb,.rpm, and universal.run. The eBPF kernel programs are compiled with Clang as part of the build pipeline; CO-RE relocations let the same binary run across distributions and kernel versions, with BTFHub providing the BTF data on older kernels that lack/sys/kernel/btf/vmlinux. - API Server: ASP.NET Core 10 running in official Microsoft Docker base image. NuGet packages for Clerk SDK, Stripe SDK, Npgsql (PostgreSQL driver).
- Frontend: React SPA built from npm packages. Static assets served via CDN.
Update & Installer Integrity
Agent and desktop updates are protected by a signed, hash-anchored chain that is verified at build time, at serve time, and again at install time. A failure at any link withholds the update rather than degrading to an unverified install.
- Build-time signing: The build pipeline signs every installer with an EV code-signing certificate issued by SSL.com, using
signtoolwith an RFC 3161 trusted timestamp. - Hash anchoring: The SHA-256 of the signed installer is written into the version manifest (
version.json) at build time. The anchored hash commits to the exact signed bytes that ship — not a pre-signing artifact — so the manifest, the signature, and the served binary cannot drift apart silently. - Serve-time re-verification (fail-closed): On every update request, the update API re-verifies the binary it is about to serve against the anchored manifest hash. On mismatch, the version is withheld entirely — the server fails closed rather than serving a binary it cannot vouch for.
- Install-time enforcement — Windows agent (2.4.0.3+): A version response without a hash is a hard failure. A downloaded installer must pass both the SHA-256 check against the anchored hash and full Authenticode validation via
WinVerifyTrust(signature mathematics plus chain to a trusted root), and the signing certificate's thumbprint must match a pinned set. Installers that fail any check are deleted; the running agent continues unaffected. - Install-time enforcement — desktop application (2.3.4+): The desktop app enforces the identical checks, on by default, sharing the same verifier implementation as the agent.
- RdpHelper signing: The
uiAccessinput helper (ETDucky.RdpHelper.exe) is independently signed and its signer is pinned, deployed on an observe-then-enforce rollout. - Rollout discipline: Enforcement is flag-gated per component, so the flag — not a redeploy — is the rollback path if a verification change misbehaves in the field.
Logging & Auditing
- Structured Logging: All API server logs use Serilog structured logging with timestamp, request path, response code, and timing data.
- Agent Connection Tracking: SSE connection/disconnection events are logged with agent ID, organization ID, and connection IDs.
- Authentication Events: All authentication attempts (bearer token and legacy) are logged. Failed authentication returns 401 with no information leakage about valid agent IDs.
- Webhook Audit: Clerk webhook events are signature-verified and logged for audit trail.
- Alert Rule Evaluation: Alert evaluations are logged per-agent with timestamps for compliance traceability.
- Script Audit: Every script creation and modification is logged with user identity, organization, timestamp, and SHA-256 content hash for tamper detection.
- Command Security Audit: Every command execution — both ad-hoc and script-based — is risk-scored and logged to
ShellCommandSecurityLogswith risk score, matched indicators, user identity, target agent, command hash, and execution decision. High-risk commands (score ≥60) generate elevated warning logs for security review.
Incident Response
Autonomous Ransomware / Compromise Detection
The always-on behavioral monitor detects and responds to ransomware and endpoint compromise automatically — before a human operator reviews the alert:
- The security ETW session (
ETDucky_Security) detects a behavioral indicator (file encryption sweep, shadow copy deletion, backup sabotage, or suspicious process spawn). - If confidence is High or Critical, Windows Firewall isolation is applied immediately — blocking all traffic except loopback and the ET Ducky API endpoint.
- A security ticket is submitted automatically to the organisation's connected ticketing system with a full markdown summary and raw evidence.
- After verifying the alert is a false positive or confirming remediation is complete, an administrator sends a remote
agent.unisolatecommand from the dashboard. The agent presents an approval popup to the logged-in device user, who must explicitly approve before firewall rules are removed. If no user is logged in, the request is permanently rejected and the org is alerted. Alternatively, a technician on-site can enter a dashboard-generated HMAC-TOTP lift code directly at the machine.
Agent Compromise Response
If an agent or its bearer token is suspected to be compromised:
- Revoke the agent's bearer token via the dashboard or admin API — immediately prevents all further API access.
- Mark the agent as inactive via the dashboard — prevents data submission.
- Investigate via the agent's historical telemetry for anomalous behavior prior to detection.
- Reinstall the agent with a fresh registration token to issue a new bearer token.
Platform Abuse Response
If the platform is being used to execute unauthorized scripts or deploy unauthorized software:
- Suspend the user account via the identity provider dashboard — revokes all JWT tokens and blocks API access.
- Revoke all registration tokens for the affected organization — prevents new agent deployments.
- Invalidate bearer tokens for affected agents — stops agent communication on next heartbeat.
- Deactivate compromised agents via the admin API — clears bearer tokens and marks agents inactive.
- Review automation rules for the organization — disable any rules referencing suspicious scripts.
- Audit the
ShellCommandSecurityLogsandshell_commandstables for full command and risk-scoring history. - Review high-risk command logs (risk score ≥60) for patterns of malicious activity.
Command Execution Security Model
All remote command execution — both ad-hoc commands and script-based — is protected by a multi-layered risk scoring and audit system:
- Risk scoring: Every command is evaluated against 18 risk indicators before execution. Indicators include known malicious patterns (C2 domains, RAT deployment tools), dangerous system operations (format, diskpart, bcdedit), credential harvesting tools, obfuscation techniques, and suspicious download patterns.
- Known IOC detection: Commands matching indicators of compromise from prior security incidents are automatically scored at the maximum risk level (100).
- Elevated monitoring: Commands scoring ≥60 are flagged as high-risk and generate elevated warning logs (
ad_hoc_high_riskorscript_high_risk) for security review. - Rate limiting: Command execution is rate-limited to 30 per user per organization per hour to prevent bulk abuse.
- SHA-256 content hashing: All commands are hashed for tamper detection and deduplication in security logs.
- Script repositories: Organizations maintain curated script libraries. Scripts can be imported from connected external repositories (GitHub, Azure Blob Storage, HTTP sources) for centralized management.
- Comprehensive audit trail: Every execution decision is logged to
ShellCommandSecurityLogswith risk score, matched indicators, command hash, user identity, target agent, and timestamp — regardless of risk level.
System/global scripts maintained by ET Ducky are pre-classified at risk score 0 and exempt from risk indicator evaluation.
Credential Rotation
All third-party API keys and secrets are rotatable via their respective provider dashboards. The deployment architecture supports seamless credential rotation without application downtime.
Geographic Restrictions
Agent registration and installer downloads are restricted to North American IP addresses. Requests originating from outside the allowed region are rejected at the network edge before reaching the application.
Vulnerability Management
- Agent Auto-Update: Agents check for updates every 6 hours. Update packages are verified against the signed-installer hash anchored in the version manifest, plus Authenticode and pinned-signer checks on the endpoint (see Update & Installer Integrity). Administrators can control update rollout timing.
- Container Updates: Docker base images are periodically updated. Application rebuilds pull latest security patches from Microsoft's .NET 8 images.
- Database Patching: Managed by DigitalOcean with automatic minor version updates and maintenance windows.
- Security Auditing: Internal security audits are conducted regularly, covering secrets management, authentication flows, network exposure, and cryptographic practices.
Compliance Matrix
The following table maps ET Ducky's security controls to common compliance framework requirements.
| Control Area | ET Ducky Implementation | Relevant Frameworks |
|---|---|---|
| Access Control | Per-agent bearer tokens, Clerk RBAC, organization isolation, admin endpoint restriction | SOC 2 CC6.1, ISO 27001 A.9, NIST AC |
| Encryption in Transit | TLS 1.2+ on all connections, WSS for WebSocket | SOC 2 CC6.7, ISO 27001 A.10, NIST SC-8 |
| Encryption at Rest | AES-256 database encryption, AES-256-GCM token encryption | SOC 2 CC6.7, ISO 27001 A.10, NIST SC-28 |
| Audit Logging | Structured logging of auth events, agent connections, alert evaluations, command risk assessments, and execution decisions with full audit trail | SOC 2 CC7.2, ISO 27001 A.12.4, NIST AU |
| Data Minimization | System telemetry plus the agent's connection IP (collected for security and abuse prevention); no end-user content, documents, or keystrokes collected; configurable retention with auto-purge | GDPR Art. 5(1)(c), SOC 2 P6.1 |
| Secrets Management | Environment variables with restricted file permissions; no hardcoded secrets | SOC 2 CC6.1, NIST IA-5 |
| Vulnerability Management | Signed, hash-verified agent auto-update; container patching; managed database patching | SOC 2 CC7.1, ISO 27001 A.12.6, NIST SI-2 |
| Threat Detection & Response | Always-on ETW behavioral monitor: file encryption sweep detection, shadow copy deletion, backup sabotage, suspicious process ancestry. Automatic network isolation on high-confidence detection. HMAC-TOTP local lift codes. Automatic ticket creation with full evidence. | SOC 2 CC7.2, CC7.3, ISO 27001 A.12.4, A.16, NIST IR-4, SI-3 |
| Incident Response | Token revocation, agent deactivation, credential rotation, geographic access restrictions, command risk scoring, autonomous isolation | SOC 2 CC7.3, ISO 27001 A.16, NIST IR |
| Third-Party Risk | All third-party services are SOC 2 certified; data sharing minimized | SOC 2 CC9.2, ISO 27001 A.15, NIST SA-9 |
| Network Security | AllowedHosts restriction, CORS policy, VPC database isolation, no inbound agent ports, geographic IP restrictions on registration and downloads | SOC 2 CC6.6, ISO 27001 A.13, NIST SC-7 |
Risk Summary for Approvers
Agent runs as LocalSystem — is this a risk?
LocalSystem is required for ETW kernel-level tracing, which is required for deep system-level tracing. The agent does not expose any network listeners and communicates exclusively outbound over HTTPS. Command execution is risk-scored and rate-limited, with every execution decision logged for audit. Shell session functionality requires explicit user initiation from the authenticated dashboard and operates under defined session boundaries.
What data reaches Anthropic's AI service?
Only aggregated telemetry summaries — CPU/memory trends, event correlation summaries, and error pattern descriptions. No PII, credentials, file contents, or raw event data is sent. AI analysis is user-initiated, not automatic. Anthropic does not train on API data per their commercial terms of service.
What happens if an agent's bearer token is compromised?
A compromised token can submit health data and ETW events as that agent, and receive pending script executions. It cannot access other agents, other organizations, or the web dashboard. All commands dispatched to the agent are risk-scored and logged, providing a full audit trail. Revocation is immediate via the dashboard or admin API and takes effect on the next request. A new token is issued upon re-registration.
Can ET Ducky execute commands on endpoints?
ET Ducky supports ad-hoc command execution, script execution, file browsing, and live queries — all initiated by authenticated dashboard users within their organization scope.
Risk Scoring: Every command — whether ad-hoc or from the script repository — is evaluated against 18 risk indicators before execution. Risk indicators detect known malicious patterns, C2 infrastructure, credential harvesting tools, obfuscation techniques, and dangerous system operations. Commands matching known indicators of compromise from prior incidents automatically receive the maximum risk score. High-risk commands generate elevated warning logs for security review.
Additional controls: All command executions are rate-limited to 30 per user per organization per hour. Script content is SHA-256 hashed for tamper detection. Every execution decision is logged with full risk assessment and audit trail. Organizations can import scripts from external repositories (GitHub, Azure Blob) for centralized script management. Agent registration and installer downloads are restricted to North American IP addresses at the network edge.
How is multi-tenant isolation enforced?
Two layers run on every database read and write:
- Application-layer EF Core query filters add the organization predicate to every query against tenant-scoped entities. A controller cannot accidentally omit it — the filter is part of the model.
- Database-layer Row-Level Security policies enforce the same predicate at the PostgreSQL level. Every command is preceded by
SET app.current_organdSET app.bypass_rlsGUCs derived from the authenticated request's tenant context. A query that escapes the EF filter is still rejected by the database.
Bearer tokens are scoped to a specific agent within a specific organization (SHA-256 stored hash; plaintext only in agent config). Lookups that must run before tenant context is established (bearer validation, webhook handlers, background services) explicitly opt in to a documented bypass scope and are flagged by an in-tree static analyzer if introduced without justification. There is no administrative backdoor for cross-tenant access; admin endpoints are localhost-only and do not provide cross-organization views.
Above the per-organization layer, organizations are grouped under workspaces (one workspace = one subdomain). The dashboard's organization picker on every page is populated from GET /api/organizations/in-current-subdomain, which filters to organizations bound to the current workspace before returning — so a user signed into one workspace can never see organization names from another, even if they are members of both. Workspace membership and Clerk organization membership are kept in lockstep by a server-side fan-out service: joining a workspace adds you to every org in it, creating an org adds every existing workspace member to it, and leaving a workspace removes you from every org under it.
Two known limitations (tracked):
- Licenses are user-owned by design (Option B) and not org-scoped at the database layer; queries filter by Clerk user id (taken from the JWT) instead. Effective tier for an organization is computed at request time as the maximum across that org's members' active licenses.
AgentTagAssignmentsandAgentConfigurationsare agent-scoped child tables that inherit organization scope through their parentAgentsrow rather than carrying a denormalizedOrganizationIdcolumn. Direct queries against these tables filter byAgentId; tenant filtering is enforced at the parent join. A planned hardening step adds the denormalized column for symmetry with other org-owned tables.
Does ET Ducky detect and respond to ransomware?
Yes. The agent runs an always-on behavioral security monitor that watches for ransomware-characteristic activity without storing any events. Four detectors run continuously:
- File Encryption Tracker — flags rapid file-extension-changing rename sweeps per process (e.g. report.docx → report.docx.locked).
- Shadow Copy Deletion — detects vssadmin, wmic, bcdedit, and wbadmin commands used to destroy backups and recovery environments.
- Backup Sabotage — catches service-stop/disable commands and registry writes that disable VSS, Windows Backup, Veeam, Acronis, and other agents.
- Process Ancestry — identifies Office/browser/PDF applications spawning shell or script-host child processes, a common macro-based initial access pattern.
When a high-confidence detection fires, the agent automatically applies Windows Firewall isolation (blocking all traffic except to etducky.com and loopback) and submits a security ticket with full evidence. Isolation is liftable remotely via the dashboard or locally via a one-time HMAC-TOTP code. The monitor can be disabled via a configuration kill switch.
What are the network requirements for the agent?
The agent requires outbound HTTPS (TCP 443) to etducky.com. No inbound ports need to be opened. The agent works behind NAT, proxies, and standard corporate firewalls. If your firewall requires explicit allowlisting, allow outbound TCP 443 to etducky.com.
Security Contact
For security inquiries, vulnerability reports, or to request additional technical detail for your security review:
📧 Contact
Email: [email protected]
Website: https://etducky.com
We aim to respond to security inquiries within 2 business days.
© 2026 ET Ducky. All rights reserved. This document is provided for informational purposes to support security evaluations. The security architecture described herein reflects the current state of the platform as of May 2026, including the v2.3 multi-tenancy hardening (PostgreSQL Row-Level Security, subdomain auto-bootstrap, agent-enforced file-transfer path policy) and the v2.4 workspace model (server-side workspace membership cascade, workspace-scoped org enumeration via /api/organizations/in-current-subdomain, and grace-period subdomain aliases on rename). ET Ducky reserves the right to update security practices as the platform evolves.