53%
of surveyed organizations reported agents going beyond their intended permissions.
CSA, April 2026 · 445 respondents; research commissioned by Zenity.
Security review · Local policy · Signed decisions
AgentGuard checks tool calls locally. The plugin does not upload prompts, tool input, tool output, file content or receipts to AgentGuard. Here is the boundary a reviewer can inspect.
Scope: the AgentGuard plugin for Claude Code, Codex and ChatGPT Work. Your host, model provider and tools have their own network behavior.
53%
of surveyed organizations reported agents going beyond their intended permissions.
CSA, April 2026 · 445 respondents; research commissioned by Zenity.
54%
reported a confirmed or suspected agent security or privacy incident during the prior year.
Gravitee, State of AI Agent Security 2026 · April survey of 750 technology leaders.
≈2×
the secret-leak rate in Claude Code co-authored commits compared with the public GitHub baseline.
GitGuardian, Secrets Sprawl 2026 · Observed association, not proof of cause.
80%
of developers bypassed AI-code security policies, according to research cited in Snyk's 2025 article.
Snyk, January 2025 · A reported survey result, not an AgentGuard benchmark.
Different populations and methods. These figures explain the review questions below; they do not measure AgentGuard's effectiveness.
Hooks never open a socket. The detached worker performs licensing and configuration requests outside the tool admission path. Its requests are listed here, including policy sync when you add a Solo key.
| Destination | What is sent | When and why |
|---|---|---|
POST /api/license/validate | License key. | The worker checks license eligibility at session start or explicit activation. |
POST /api/license/seats | license_key, machine_fingerprint, process_id, org_policy_sha256 or null. | Registration, then a heartbeat about every five minutes while the session is live. |
GET /api/org/policy | License key in the Authorization Bearer header. No request body. | Separate configuration lookup at session start and every fifth heartbeat. Solo receives its personal policy; Team receives its admin-published policy. Unpublished policies receive no content. |
PUT /api/org/policy | Solo license key in the Authorization Bearer header; Content-Type: application/json; body {"policy":{...}} containing only validated policy configuration. Maximum 64 KB. No key inside the body. | Only when you run node runtime/policy-cli.cjs push. The detached worker uploads it. The response is the same version, publication time, SHA256 and policy envelope as the GET. |
The default destination is https://agentguard.run. An operator can override only the license-validation base URL with AGENTGUARD_LICENSE_ENDPOINT; seat and org-policy endpoints stay fixed. Free sessions without a license key make no licensing fetch. The two POSTs carry identifiers only. Policy GET and PUT share a third endpoint. Policy requests are limited to 120 per IP per minute, with 60 GETs and 10 PUTs per license per minute. Failed Solo sync requests select the local policy and do not cause a tool denial. The license key is a credential and should be kept private. HTTP connections also expose ordinary connection metadata such as source IP. A matching policy hash reports a loaded version; it does not attest enforcement.
Tool arguments and output, prompts, file content, provider keys, signing keys, signed decisions, input hashes and byte counts are not sent by these requests. Guard Pack matching uses arguments in memory and records rule IDs, not the arguments.
The dashboard stores the org policy your admin publishes, machine labels, revocation state and invite addresses. Solo stores the policy configuration you explicitly push. The upload selects allowed policy fields from the local configuration; it does not upload local files, the license key or unrelated settings. Free users have local presets and customization without a network request. The policy uses a strict field allowlist; custom prompt or document fields are rejected.
Installation can download packages from registries. Your host still calls its model provider, and an allowed tool can make its own requests. This inventory describes the plugin's runtime, not every program on the machine.
This comparison describes a cloud service that uploads session data, grades it on a server and requires approval before a tool runs. Products vary; it is not a claim that every cloud monitor uses that architecture.
Local hook overhead: p50 98.869 ms; p95 105.765 ms. Added inference tokens: 0.
Measured 2026-09-20 on Mac14,6 (Apple M2 Max, darwin), Node v22.17.1 arm64, using 1,000 synthetic tool-hook invocations after one excluded worker warmup. Wall time includes Node startup, local rule checks, file IPC and a signed decision. The separate Burn hook and session startup are not measured. Read the benchmark record and samples. Its authored synthetic commands describe the test; they are not customer session content.
False positives on 356 benign commands: 0.
Measured 2026-09-20 on Apple M2 Max (darwin), Node v22.17.1 arm64. Static command strings were scanned, not executed. Hard-reset examples use an explicit feature-branch context. This result covers the named corpus, not arbitrary commands. Read the corpus measurement.
Fail-open means loss of protection can allow an action. It is an availability choice, not evidence that the action was safe. Host permission checks still apply.
The example below comes from a synthetic local command processed by the real plugin. It contains decision metadata and a cryptographic signature, without the command arguments or output text.
Synthetic local benchmark receipt. No customer session. The example records an allow decision for Bash. Download the receipt and public key.
{
"note": "Synthetic local benchmark receipt. No customer session.",
"public_key_hex": "1587ee82dcd2d77fd62f0fb37f6c45d4e62e384f678cb70dfd7578ef459ea51b",
"receipt": {
"sequence": 0,
"decision": {
"actor": {
"tenantId": "synthetic-overhead",
"agentId": "synthetic-overhead",
"sessionId": "synthetic-overhead",
"provider": "codex"
},
"decisionId": "363be4ac-1ef5-46d4-963b-64211b59c8b8",
"timestamp": "2026-09-20T19:31:20.651Z",
"action": "allow",
"triggeredCap": null,
"triggeredScopeKey": null,
"projectedCents": 0,
"windowSpendBefore": 0,
"windowSpendAfter": 0,
"provider": "codex",
"modelRequested": "Bash",
"modelResolved": "Bash",
"policyId": "agentguard-codex",
"policyVersion": 1,
"enforcementMode": "enforce",
"reasons": [
"tool_policy_allowed"
],
"costBasis": {
"inputCentsPerKtok": 0,
"outputCentsPerKtok": 0,
"rateSource": "override:manual"
},
"plugin": {
"host": "codex",
"schema": "agentguard.codex.v1",
"requestId": "c71005d5-510d-49ed-8e1e-187630065d32",
"gate": "spend",
"toolName": "Bash",
"toolUseId": "overhead-warmup",
"sessionId": "synthetic-overhead",
"inputSha256": "e4f9dad917af7e49307be421d1743f1c5eb5f2e44810357d150721d659b68ef6",
"inputBytes": 32,
"inputKeys": 1,
"startedAt": "2026-09-20T19:31:20.552Z",
"event": "decision",
"capabilityTier": "data_write",
"unitCostCents": 0,
"chargedCents": 0,
"chargedWindows": [],
"license": {
"paid": true,
"tier": "startup",
"seatsUsed": null,
"seatLimit": 10,
"expiresAt": "2026-09-21T19:31:20.508Z",
"mode": "enforce",
"reason": null,
"offlineGrace": false
}
}
},
"previousHash": "0000000000000000000000000000000000000000000000000000000000000000",
"entryHash": "4cb1b599f8a51605850bc111406235457008f85eb565cedbc5ff7a386e4da907",
"signature": "7ddb87ee4f5d597c20e81817606820c5b524ac0ea60db527d96f4712b47819a3bf7a1c58a413fc4e0dce8eee8ee96ef8ce6e50aed187a97a1eae813b135be808",
"signerFingerprint": "3d0245b28ea0e960",
"publicKeyHex": "1587ee82dcd2d77fd62f0fb37f6c45d4e62e384f678cb70dfd7578ef459ea51b"
}
}Receipts include a tool identifier, input SHA-256, encoded byte counts, actor identifiers and decision or outcome fields. Outcome rows link to the earlier decision. Missing host success evidence stays unknown. A valid signature shows that the signed bytes match the key; it does not prove that the host executed the tool or that every action was recorded.
| Cost | What to inspect | Limit |
|---|---|---|
| Hook overhead | Measured local latency in the benchmark above. | A machine-specific observation, not a latency guarantee for every host or cold start. |
| Model grading | Local rules use no inference tokens. | Host and tool model usage remains separate and can still incur charges. |
| Configured tool charge | A policy may assign a unit cost and apply scoped caps. | An unpriced tool defaults to zero configured charge; that does not make the tool free. |
| Provider usage | Your provider's usage record and invoice. Burn can explain local recorded token usage. | API list-price equivalents are not a subscription bill or a promise of avoided cost. |
Free Enforce on one machine, Solo at $19 per month or $190 per year for up to three machines, and Team at $199 per month or $1,990 per year for ten seats; provider usage is billed separately.
Rules cover tool calls the host sends to trusted hooks. Disabled hooks, unsupported host paths and tools outside that boundary are not governed. Protect policy and hook configuration when they are organizational controls.
Actor IDs, tool names, input hashes and local paths can reveal context even without content. Restrict access to local ledgers and signing keys. Export only to a destination you choose.
A timeout or failure allows the call and records a reason when local logging is available. A dead worker, full disk or inaccessible directory can leave a gap. An absent receipt does not prove an action did not happen.
Guard Pack rules use fixed built-in IDs and stop, warn or off modes. They are not a complete shell interpreter, a malware detector or a proof that allowed code is safe. Review the rules and the benign test corpus.