Guard is endpoint detection for AI agents that runs alongside an existing EDR. It does no malware, memory or ransomware detection. Each line below is a current limit, not a promise of future work.
Platforms
macOS
- On macOS the sensor observes and reports; it does not block.
esloggerdoesn't log anything started from its own pipeline.- Processes started before the sensor come from a snapshot: their signatures are read with
codesignrather than validated by the kernel, commands already running aren't reported, and without root only the user's own processes are read. - Network flows come from polling
lsof, so short connections can be missed, until a Network Extension provider is installed and the sensor runs with--network extension. The Network Extension path is tested by replay only. - Install, update, rollback and removal of the LaunchDaemon have not run on a real Mac. The Endpoint Security system extension is deactivated by the app, not by
guard-update uninstall.
Linux
- Process and file collection use the process connector and fanotify. eBPF is used for network flows only, and only with
--network ebpf. - Signed staging releases are published, but APT and DNF repositories and their repository signing key are still pending. Packages have been tested in containers and virtual machines, not on a bare-metal x86_64 host.
- The AppArmor and SELinux policies ship in complain and permissive mode. Enforcing mode is an administrator opt-in.
- dnf on Fedora and Rocky Linux 10 accepts repository metadata signed by an expired or revoked key, and APT on Debian 13 accepts metadata signed by an expired key. These are upstream package-manager behaviours.
- Managed Linux endpoint hooks don't get a device ID from enrollment yet, so device-based policy selection falls back to the strictest profile, and identity-aware rules see an unknown identity.
- On a system-enrolled package, kill switches and quarantines from Guard Cloud land in the system Guard home, not in per-user or managed-endpoint hook state.
Windows
- Windows support is component-specific. The new VS Code, Kimi/Qwen, Chrome DevTools MCP and local-runtime paths have no retained native Windows live qualification.
- On Windows, publisher checks cover only Claude Code, Claude Desktop and Cursor. Other tools are identified by name and interpreter arguments, and revocation isn't checked.
- Command lines of short-lived processes need kernel process events or audit event 4688. Without them they are missing, and the sensor's health says so.
- File opens are reported after the fact, so reads can't be seen as they happen or blocked.
- Network events are TCP connections, with the bytes they send as a running total, and UDP datagrams. They carry no duration or outcome, and nothing is blocked.
- Windows ships as a zip with
install.ps1or a per-machine MSI. Update, rollback and uninstall passed on a Windows machine, including a power cut, but Cloud sync of those events wasn't run. - Boot recovery after an interrupted update is opt-in (
guard-update.exe enable-boot-recovery, elevated); neither installer registers it.install.ps1 -Uninstallremoves it; the MSI uninstall doesn't. It was tested by starting the task, not by a reboot. - The first sensor start after an install or upgrade causes a one-time CPU and memory spike while it checks the signatures of AI tools already running.
- The sensor runs as LocalSystem, which can read every user profile.
- Screen capture through Graphics Capture or Desktop Duplication isn't detected.
- Identity-aware rules see an unknown identity, and native control-file write notices are not available.
- Windows has no
SIGSTOP, so remote process kill holds the agent's process tree in a job object before killing it. Network isolation hasn't run live on Windows. Local model detection has, for llama.cpp's server only; other runtimes on Windows are covered by tests, not live runs.
Shared code not built for every platform
- Several features were built and tested on macOS only, with Linux and Windows sharing the code but not yet compiled or qualified for them: session taint, attack paths, session handoffs, model-assisted detection, policy authoring, policy remediation, MCP registry discovery and the MCP gateway.
Harnesses and hooks
See Hooks for how hooks work.
- Hook payloads change between harness releases without notice.
- Live testing covers specific versions: the Cursor CLI was validated live; Claude Code's tool hooks ran live on Windows and in WSL2; Copilot CLI and Gemini CLI were run offline against a scripted local model; the Cline VS Code extension against a local model. The Cursor editor and Windsurf were checked by their package contents and not run live.
- Copilot CLI and Gemini CLI still run the action when a hook times out or replies with invalid output. That is a fail-open gap, not prevention.
- The Cursor CLI doesn't fire
beforeSubmitPrompt. - The Cline VS Code extension passes
[object Object]instead of tool output to its post-tool hook, so secrets in output reach the model unscanned, and it ignores an invalid hook reply. - Cline ignores hooks that fail or time out, and the Cline CLI doesn't wait for prompt hooks, so it can't block prompts.
- For Claude Code's and Cursor's non-MCP tools, output has already reached the model, so Guard can only tell it not to repeat a secret. Windsurf's post-hooks can't change output, so output isn't scanned there.
- Where a harness can't ask for confirmation (Codex, Gemini CLI, Windsurf, Cline),
askrules only warn. Copilot CLI can't show a warning, sowarnrules are silent there. Cursor'spreToolUsecan only block or allow file writes. - Encoded secrets are reported, never blocked, and only when they decode to a known secret pattern. In prompts they are checked only under the human-to-AI sharing opt-in, and only the first 64 decodable tokens.
- Shell analysis follows variables, globs, scripts,
evaland substitutions up to four levels deep. Strings built at run time, paths assembled inside programs, scripts in other languages and native API calls are not followed. - Pre-action checks cover the agent's own write tools and shell redirections, not writes that other programs make, such as a script rewriting
settings.jsonor a build tool writing.git/hooks. - Agent flags passed through a wrapper (
npx @openai/codex --yolo), SQL in a here-document or file,cp -t DIRandsudo -u USERkeep analysis gaps. - Package look-alike checks compare command-line names and supported installed-package manifests with finite popular-name lists for npm, PyPI, crates.io, NuGet and RubyGems. Go has no list. They don't prove a squat is malicious or discover every transitive dependency.
- The check for names not on the registry covers npm, PyPI and crates.io names on an install command line only, not manifests, lockfiles or
guard scan. Guard ships no name snapshot, so with no snapshot installed and registry lookups off (the default), nothing is reported. A snapshot is a point in time, and about 0.8% of missing names read as present. Private registries are read from.npmrc, pip and Cargo configuration and environment variables only; one set any other way, such as a plugin, a wrapper script or a flag Guard doesn't parse, isn't seen, so its packages are reported until allowed. On a managed endpoint, a route created afterguard packages names installran needs the install run again. Lookups send the package name to the public registry. - Prompts can't be exempted, command exceptions match one simple command only, and server exceptions may not apply in Copilot CLI and Cursor's
postToolUse. - A person can remove Guard's hooks, switch hooks off in harness settings or run
guard hooks uninstall. Agents that try are blocked.guard hooks repairrestores partial or broken hooks. - Continue, Aider and Zed are inventoried but have no pre-action hook, so Guard doesn't block in them. The Continue CLI loads hook settings but doesn't fire them.
- VS Code's Copilot Session Target shares the Copilot runtime adapter; Legacy Local is a separate, unsupported protocol. Its editor path has fixture tests, not retained live qualification. Server and tool access rules and Console MCP blocks need gateway adoption there. An extension being installed, or a Code process running, does not prove an AI session or hook delivery.
- Kimi Code's current Node runtime and Qwen Code's CLI/companion have native adapters checked against reviewed source and synthetic fixtures, without an installed-client, model-backend or OS live result. Kimi's asynchronous output preview cannot withhold output. Qwen output withholding is limited to reviewed classic/ACP dispatch paths, and a Qwen build that follows its own hook documentation may end the turn when Guard withholds output. Both vendors can continue after hook errors or timeouts; neither supplies independent OS enforcement or Guard's exact-call approval workflow.
- JetBrains AI Assistant is observe-only.
- Kiro:
UserPromptSubmitblocks only in the IDE,PostToolUsecan't withhold output, and no Kiro build has been run live. - Amazon Q Developer: CLI hooks are written only into agent files that already exist, the built-in default agent has none,
userPromptSubmitcan't block, and IDE agents are inventory only. guard hooksdoesn't manage Windsurf's system-level files, JetBrains plugin files, or Gemini CLI settings that contain comments.- The optional local OpenTelemetry intake is not vendor-qualified: it doesn't prove which process wrote a message, macOS connections stay uncorrelated, and Windows isn't supported.
Browser AI
- The browser monitor is a per-company opt-in, and it follows the privacy settings in the signed catalog. A device without that catalog keeps it off.
- The browser extension doesn't match custom data identifiers.
- Inventory doesn't fully cover Firefox extension packages or most agentic-browser installations.
- Shadow AI: with the human-to-AI sharing opt-in, Chrome's extension counts directory-app visits and shows warn and block pages; one request can reach a site before its block page. No network fallback or daily-row retention yet.
Endpoint sensor
Keychain, clipboard and credentials
- On macOS 14 to 26, keychain requests that go only through the legacy
com.apple.SecurityServerpath aren't seen. A finding says a request was made, not which item or whether access was granted. NSPasteboardon macOS and libsecret or toolkit clipboard APIs on Linux are invisible.- On Linux, clipboard reads through GTK, Qt, Electron or the display server directly aren't seen.
- Collectors keep at most 64 arguments of an exec, 32 KiB of any one and 64 KiB in all. During a flood of execs, each keeps only 8 KiB. A longer inline script can hide a call, and Guard then reports
command_not_fully_inspected. The Linux open hook copies only 512 bytes of the opener's arguments. guard credentialsis local only: it isn't uploaded or shown in the Console. Environment variables and MCP configuration use can't be observed, and tokens held inside an agent's own process aren't listed.
Privacy permissions and screen capture
- The sensor's TCC grant reporting needs macOS 15.4 or later, names apps at name level only, and sees only grants made while the sensor runs.
guard scanlists the Full Disk Access, Accessibility and Input Monitoring grants that catalog AI tools already hold. Of the permissions a host app such as Terminal or VS Code already held, it knows only screen recording. Synthetic input grants aren't read.- On macOS,
CGWindowListCreateImageandCGDisplayStreamcapture isn't seen, and a ScreenCaptureKit connection that only lists windows looks like a capture. guard scanneeds Full Disk Access to read the TCC databases; without it each is reportednot_available.- On Linux, a portal screen-capture request is reported, not whether the user allowed it. X11
XGetImageand compositor-private screenshot interfaces aren't watched.
Local and hosted models
- Inventory includes MLX-LM and SGLang alongside Ollama, LM Studio, llama.cpp, vLLM, LocalAI, Jan, GPT4All and LiteLLM. Model-family names are not an allowlist: DeepSeek, Kimi, Qwen and an arbitrary-name control appear in fixtures, without live model qualification.
- Only Ollama-compatible
/api/psreports memory-resident models. OpenAI-compatible/v1/modelslists served or available IDs, which may include cached or unloaded models. An API-key challenge isauth_required, with unknown models; Guard sends no key or inference request. - Generic or custom ports require positive listener identity. Linux and macOS can inspect a Python listener's script or module; installation plus a bare Python owner is insufficient. Windows has no listener-argument lookup. Custom wrappers,
python -cand genericuvicorndo not identify a runtime. - LAN-only listeners, container proxies and sockets the OS cannot attribute are not probed. Read-only model requests go only to the observed loopback listener, without credentials or redirects. Shared caches are not assigned to one runtime, and a local proxy may forward to a cloud service.
- Model names are uploaded as given only when they look public: a bare name, or an
owner/namewhose owner is on the catalog's list of public publishers. Other names are uploaded as a keyed hash. A bare name is uploaded as given even when a user made the model locally. - Real Ollama and llama.cpp runs are retained for Linux containers. Other listed runtime paths, including MLX-LM and SGLang, have fixtures rather than live qualification. A llama.cpp server was also found live on Windows. WSL belongs to its Linux environment; other native Windows runtimes and every upstream-supported OS are not claimed.
- Hosted DeepSeek, Kimi/Moonshot and Qwen recognition uses catalog API destinations, independently of model names. It proves neither successful inference nor intercepted tool calls. Custom proxies need an exact organization catalog entry. IP-only pollers cannot infer wildcard workspace hosts; they need the exact host. Chat-site directory entries are separate and remain behind the human-to-AI sharing opt-in.
Data access view
guard data-accesscounts completed opens by agent processes. Attempted or prevented access, hook-mediated reads, memory-mapped files and data from the network or MCP servers aren't counted.- Data classes come from paths, not content. SaaS labels such as Microsoft Purview are out of scope.
- Counts are lower bounds when limits are hit, and the Windows collector isn't qualified.
Agent inventory
- Inventory is driven by known install locations and recognised processes. Binary plists, opaque IDE state and behaviour-only discovery aren't complete.
- A system service sees its configured user's home, not every user's home.
Posture scan and content
See Scan.
guard scanreads settings files only. Editor-internal state (Cursor auto-run, Windsurf Turbo, Cline auto-approve), MDM profiles, Windows registry policies other than Claude Code's, VS Code's AI policies and server-delivered settings aren't read.- The sensor reports an agent CLI started with a bypass flag (
--dangerously-skip-permissions,--yolo,--allow-all-tools) or withCLAUDE_CONFIG_DIR,CODEX_HOME,COPILOT_HOMEorCURSOR_CONFIG_DIRset. Flags are seen on Linux, on Windows and throughesloggeron macOS (within the argument limits above). The environment is seen only on Linux, while the process runs, and througheslogger. With the native macOS client or on Windows, a CLI started with only a moved directory isn't reported, and the sensor's health says so. - Gemini CLI and Cline have no directory variables in the catalog yet. A flag set in a configuration file or added by an alias inside the CLI isn't seen, and
guard scanreads a moved directory only when the variable is set in its own environment. - Effective values are approximate: absent settings with risky defaults aren't reported, admin constraints aren't applied, and profiles are reported whether or not they're selected.
- Content scanning is pattern-based. Percent-encoding, HTML entities, ROT13 and compressed encodings aren't decoded, and paraphrased or translated instructions aren't matched.
- Memory and rules files in project subdirectories are read within bounds: eight levels deep, 16384 directories, 512 files and 16 MiB per project. Hidden, vendored, build and
.gitignored directories are skipped, so a plantedCLAUDE.mdthere, or deeper, isn't read. Nested skill, hook and settings files, and memory kept in a database or on a vendor's servers, aren't read. - Planted instructions written by a script, sync tool or editor are labelled outside agent tool calls, and only at the next
guard scan --context-changes. - Package scanning is static and line by line. It misses behaviour built at run time or hidden by obfuscation. A finding means code mentions a behaviour; no finding isn't proof of safety.
- Credential findings use known secret patterns and locations only.
.envfiles in project subdirectories, shell profiles,~/.npmrc, IDE databases and OS keychains aren't read. guard scan --cisees only the repository. User, system and managed settings on developer machines aren't read, and MCP tool definitions aren't fetched.- The scan is point in time.
guard posture monitorwatches only approved posture settings and MCP servers, not settings outside files, flags or the environment. Drift findings aren't committed to the findings chain. The latest drift evaluation and approval history upload to Guard Cloud on sync; setting values, paths, approver and reason stay on the device.
Limits in Guard Cloud, the Console, sessions, policy, response and privacy are in Known limits: Cloud and Console.
Written from docs/known-gaps.md, docs/positioning.md, docs/local-models.md, docs/hosted-models.md, docs/vscode-copilot.md, docs/native-model-clients.md, docs/detection-catalog.md at commit fb79778d02f0. Rune Guard is in early access.