Device Agent Privacy and Consent
Status: PRIVATE PREVIEW
This page is for enterprise administrators and security teams who deploy the
Control Zero device agent (the cz-agent binary, service cz-agentd) and need
to know exactly what data leaves a device and what consent or privacy controls
exist. It describes the device agent's current behavior and states where a
control does not exist.
This page is about the device agent only. The separate shadow-AI discovery component has its own documentation.
The collection boundary
The device agent emits seven groups of structured data. Each one is a closed, typed wire structure, and each one is enumerated here so the boundary is explicit rather than implied.
1. The local hook protocol
When a governed host tool fires a hook, a shim forwards the call to the daemon over a local socket. Three types cross that boundary:
HookRequest— what the host chose to run:canonical_source(the host name),payload(the tool input as JSON, forwarded unchanged so the policy can be evaluated),cwd,git_remote(optional),shim_version,shim_signature, andshim_asserted_ancestry.Provenance— what the daemon observed about the connecting peer:peer_pid,peer_uid,peer_sid,peer_exe_path, a content hash of the peer executable,ancestry_observed,shim_signature_valid, and averdictstring (host | not_host | unknown). A field the kernel cannot supply isNone, and the peer identity fields are observed by the daemon, never taken from the request.HookDecision— the finalised result returned to the shim:verdict(allow | deny | warn | hitl),origin(the deciding layer), the observedprovenance, and an optionaldlpoutcome.
The findings in a decision's DLP outcome never carry matched bytes.
masked_input redacts only spans matched by a mask rule, so text matched only
by a detect rule stays in it unchanged:
DlpOutcome—action(detect | mask | block),findings,uncompilable_rule_ids, andmasked_input. Each finding names the rule, its category and its action, not the matched text.masked_inputis present only when a mask fired and the call proceeds: it is the tool input with the spans matched by mask rules redacted. Everything else, including text matched only by a detect rule, appears unchanged.DlpFinding— arule_id, the org'scategory, and theaction; nothing else.masked_inputis present only when a mask fired, changed the input, and the verdict lets the call proceed — the caller runs the tool on the redacted input instead of the original.
2. Discovery rows
The discovery detectors return AiDiscovery rows. The row shape is:
id,discovery_type(ai_traffic | ai_process | ai_api_key | ai_tool),summary,details(a metadata-only string map),severity,first_seen,last_seen, andhostname.
The details map is where the privacy boundary is enforced. The module defines
a hard list of forbidden detail keys — argv, args, argument, command,
cmdline, cmd, env, environ, api_key, token, secret, password,
value, credential — and the forbidden-key check flags any detail key that
contains one of these strings, case-insensitively, naming the offending key.
The process and traffic detectors' tests fail any row they emit that trips it.
The key and host detectors have no such test.
What each detector actually reports, rather than what it saw:
- Key scanning reports only
file_path,line_number,key_type, andkey_prefix(the first 8 characters of the matched text plus...). The key value is never returned or transmitted. - Process scanning reports only
process_name,pid, the owner's user id, the matched tool label (tool) and, when more than one instance matched,instance_count. Command-line arguments — which may contain API keys or secrets passed as flags — are deliberately not transmitted. - Traffic scanning reports only the endpoint (a known AI API hostname, or
localhost:<port>for a known local inference port), a label, aportfield that is always the literal443, and a connection count. These are read from the active TCP connection table on Linux and macOS. On Windows it reports nothing. No payload data is captured. - Host detection reports the host name, the config
path that proved presence, and an optional semantic-version string read from
the host binary's
--versionoutput. Config file contents are never read into a row.