End-user identity
Understand how DefenseClaw attributes telemetry to endpoint users and agents, which identity facts are verified or claimed, how to join records, and how to opt in to the principal and connector email.
DefenseClaw attributes hook activity and per-profile AI inventory to the endpoint account that produced it. This matters on shared endpoints, where the gateway's service account is not the person running the agent.
An absent field means DefenseClaw could not establish it safely. Do not infer id_kind from an identifier's shape, and do not build an email from an account name.
| Attribute | Meaning |
|---|---|
user.id | POSIX effective uid or Windows token SID. |
defenseclaw.user.id_kind | posix_uid or windows_sid, set only when the id came from the matching trusted OS source. |
defenseclaw.user.name | OS account name without its domain: alice for the SSSD account alice@corp.example.com or for CORP\alice. The qualified form is the principal. Every record of the account carries the same spelling. A local and a directory account with the same bare name differ by user.id, defenseclaw.user.directory and defenseclaw.user.domain. Names in any script are kept. |
defenseclaw.user.email | Optional connector-account email. Off by default. |
defenseclaw.user.principal | Directory principal (UPN, Kerberos principal or DOMAIN\user), for example alice@CORP.EXAMPLE.COM. Sent only with ai_discovery.include_user_principal. |
defenseclaw.user.domain | Directory domain or Kerberos realm. |
defenseclaw.user.directory | local, ldap, active_directory, entra_id, okta or other. |
defenseclaw.user.tenant_id | Cloud directory tenant, for an Entra-joined Windows account. |
defenseclaw.user.identity.source | The OS facility that resolved the directory facts. |
defenseclaw.user.principal.assurance | verified when the gateway or the root guardian resolved the facts. claimed when only the hook reported them (defenseclaw.user.identity.source is then hook_reported). |
defenseclaw.session.kind | local, ssh, rdp or console. Reported only when it has the same assurance as the directory facts. Only Linux verifies a session, so Windows and macOS records omit it. |
client.address | Client address of an SSH or remote session, reported with the session kind. |
defenseclaw.session.kerberos_principal | Principal of the session's Kerberos ticket cache. Always claimed. Sent only with ai_discovery.include_user_principal. |
defenseclaw.agent.identity.id | The agent's stable identity (agt-), one per connector install, user and machine. |
defenseclaw.guardrail.profile.name, .digest, .match, .matched_group | The guardrail profile that decided the request, its policy digest, why it was chosen, and the matching group. |
defenseclaw.user.group_count | On the identity.observed record only: how many groups the user has, never their names. |
The directory fields come only from the operating system; DefenseClaw never calls an identity provider. See How DefenseClaw knows who a user is and Identity and authentication. The Secure Client profile emits none of the directory, session, agent identity or profile attributes.
Attribution, not authorization
Hooks run in the interactive user's session, read the account from the operating system, and send it to the loopback gateway as X-DefenseClaw-User-Id and X-DefenseClaw-User-Name. Those headers, and a user named in a hook payload, are claims. On the routes below the gateway ignores the claim and names the user it authenticated, so a forged header cannot re-attribute a record.
| Route | Per-user install | Standalone enterprise |
|---|---|---|
| Hook and inspect | The gateway's own account | The peer uid of the hook socket, or the uid or SID of the per-user credential. A request whose headers name another user is refused with 403. |
| ACP | The gateway's own account, for signed requests and bearer tokens | The user bound to the ACP enrollment credential, one per user, editor and agent (preview). |
| LLM proxy | The gateway's own account when the request presents the gateway token or master key. The X-DefenseClaw-User-* pair is removed from every request. | No user is bound. The pair is removed. |
| Sandbox ingress | The host user on the sandbox binding, recorded for attribution without verified facts. Identity headers from the sandbox are ignored. | Same. |
| Other routes that take the gateway token | The gateway's own account | No user is bound. |
A request that proves nothing has no verified user. Application fields such as an X-User-Id header or a body user are recorded as a label, without id_kind, and only when no user was verified. They never choose a guardrail profile.
Do not authorize from telemetry identity
The hook identity is a join key, not an authenticated principal. A local process with a connector hook token may be able to supply a hook request. Never grant access from these fields.
Join hook activity to inventory
Hook lifecycle records carry identity in the agent.lifecycle, tool.activity and guardrail.evaluation buckets. Findings and scan verdicts of an inspected request carry it in security.finding and asset.scan. Per-profile MCP inventory carries it in ai.discovery.
| Record | What it adds |
|---|---|
hook.decision, guardrail.evaluation, tool.activity, and agent, model, tool and guardrail spans | The account, directory, session and agent identity attributes, and the guardrail profile on decisions. |
identity.observed | Once per user per identity cache lifetime (15 minutes): directory, source, assurance and group count. |
ai_component.* and the endpoint inventory | The owning user's principal, domain, directory, assurance and agent identity. |
ide.plugin.discovered, changed, removed | One IDE plugin and its enabled state, for the user who owns it. |
To follow one agent across sessions, join on defenseclaw.agent.identity.id. Join on user.id only after checking defenseclaw.user.id_kind; never join a POSIX uid to a Windows SID. In managed enterprise mode the gateway runs as a service identity, so inventory takes the owner from each profile directory's file ownership or token-bound Windows Known Folders.
Optional connector email
Email is off by default and has no CLI or TUI switch. After you review the privacy impact, add this to ~/.defenseclaw/config.yaml and run defenseclaw config validate:
config_version: 9
ai_discovery:
include_user_email: trueA running gateway applies it on the next reload. On a managed deployment the administrator edits the machine configuration.
| Connector | Source |
|---|---|
| Claude Code | oauthAccount.emailAddress in the profile's .claude.json, on the owner's ai_component.observed records |
| Codex | The email claim of the ID token in the profile's .codex/auth.json, on ai_component.observed records. Treated as inventory evidence, not an authenticated assertion. |
| Cursor | user_email in the hook payload, on hook activity |
On a managed host the hook guardian reads each enrolled account's own profile; you do not list profiles. An address never goes on a record without a user or on another account's record. A file the reader cannot safely open (a link out of the profile, or any link on Windows) gives no address and a named include_user_email warning in the hook guardian log (C:\ProgramData\Cisco\DefenseClaw\logs\guardian\hook-guardian.log on Windows). A per-user gateway does not attach these addresses to AI discovery rows. To get a connector email, join a hook event to the latest ai_component.observed with the same user.id; it is reported once per discovery cycle.
Email is plaintext in most profiles
none, sensitive and content send the address as plaintext to every configured destination, including the managed AI Defense destination. Only strict, or a custom profile that extends it, removes it. On the Secure Client profile every profile keeps it.
Optional principal
No record carries defenseclaw.user.principal or defenseclaw.session.kerberos_principal unless you opt in. The domain, directory, source and assurance are sent either way.
config_version: 9
ai_discovery:
include_user_principal: trueThe option applies to the whole gateway. To send principals to a trusted local Loki but not to a SaaS destination such as Galileo, turn it on and give the other destination the strict profile.
The option governs the two principal attributes only. On a Linux host joined with SSSD fully qualified names (use_fully_qualified_names = true), the home directory is /home/alice@corp.example.com, so any record that contains a home-directory path contains the UPN whatever this option says. That includes the rule-pack directory of a hook decision, health errors, AI discovery roots and defenseclaw-gateway audit export. Paths are the path field class: sensitive and content hash them, strict removes them, none keeps them. Free text is not path-aware: a command or prompt that names the home directory keeps it under sensitive, which detects emails but not an account name in a path; content and strict replace or remove that text.
Every redaction profile preserves defenseclaw.user.name. Except under the Secure Client integration, that is the bare account name (alice) on every record, IDE plugin records included. The qualified form alice@corp.example.com is only the principal, which strict removes. If a destination must not receive even the bare account name, do not send it user-attributed telemetry: keep that route on a trusted destination or disable the export. See Redaction.
See AI discovery for profile inventory and the IDE plugin inventory.
Observability
Configure logs, traces, metrics, redaction, local history and independent export destinations from one observability graph.
Local observability stack
One-command OpenTelemetry + Loki + Tempo + Prometheus + Grafana stack, pre-wired to the DefenseClaw gateway. Grafana on :3000, dashboards seeded, no manual config.