From pki.sgit.ai, the page as fetched on 2026-09-25 · open the live page ↗Everything on this sheet is the source site's own text; the newsroom's chrome is outside it.
{
"version": "2026-08-21",
"basis": "Every tree here is derived from what a surface ARCHITECTURALLY is, not from a security assessment of any vendor. That a command-line agent running under your account can reach what your account can reach is a fact about command-line programs, true of all of them, and it is not a claim about whoever wrote one. Where a node comes from something stronger than that — a published third-party audit, or a direct measurement — the node says so and carries its date.",
"evidence": {
"derived": "Reasoned from what the surface is. True by construction, and nobody has checked this instance.",
"third-party": "From a published read-only audit tool's module list, so the row is comparable with something public.",
"measured": "Observed inside a running installation on the stated date. One vendor, one surface, one date. Not generalised.",
"tested": "The boundary was probed by making requests rather than by reading documentation."
},
"tiers": {
"boundary": "Enforced by something outside the grant — the OS, a separate account, a container, a network policy. It holds against a compromised agent.",
"setting": "Enforced by the tool itself, running inside the grant. Anything that can run code here can go around it.",
"expectation": "Enforced by nothing. Written in a prompt or a rules file. It is a mandate, not a control.",
"none": "No mechanism is claimed. This is simply reachable."
},
"surfaces": [
{
"id": "cli",
"label": "A command-line agent",
"where": "your machine",
"oneline": "Runs under your user account, so it inherits your account's reach.",
"icon": "terminal"
},
{
"id": "desktop",
"label": "A desktop application",
"where": "your machine",
"oneline": "Also runs as you — the difference from a CLI is which prompts are on by default, and a default is a setting.",
"icon": "window"
},
{
"id": "web",
"label": "A hosted assistant",
"where": "the vendor",
"oneline": "Reaches what you paste in and whatever connectors you switch on. Not your filesystem.",
"icon": "cloud"
},
{
"id": "agentbox",
"label": "A hosted agent container",
"where": "the vendor",
"oneline": "A container you do not control, holding the repository you attached to it.",
"icon": "box"
}
],
"products": [
{
"id": "claude-code",
"surface": "cli",
"label": "Claude Code",
"vendor": "Anthropic"
},
{
"id": "codex-cli",
"surface": "cli",
"label": "Codex CLI",
"vendor": "OpenAI"
},
{
"id": "gemini-cli",
"surface": "cli",
"label": "Gemini CLI",
"vendor": "Google"
},
{
"id": "other-cli",
"surface": "cli",
"label": "Another CLI agent",
"vendor": ""
},
{
"id": "claude-desktop",
"surface": "desktop",
"label": "Claude Desktop",
"vendor": "Anthropic"
},
{
"id": "chatgpt-desktop",
"surface": "desktop",
"label": "ChatGPT Desktop",
"vendor": "OpenAI"
},
{
"id": "other-desktop",
"surface": "desktop",
"label": "Another desktop app",
"vendor": ""
},
{
"id": "claude-web",
"surface": "web",
"label": "Claude (web)",
"vendor": "Anthropic"
},
{
"id": "chatgpt-web",
"surface": "web",
"label": "ChatGPT (web)",
"vendor": "OpenAI"
},
{
"id": "mistral-web",
"surface": "web",
"label": "Le Chat (web)",
"vendor": "Mistral"
},
{
"id": "other-web",
"surface": "web",
"label": "Another assistant",
"vendor": ""
},
{
"id": "claude-code-web",
"surface": "agentbox",
"label": "Claude Code on the web",
"vendor": "Anthropic"
},
{
"id": "other-agentbox",
"surface": "agentbox",
"label": "Another hosted agent",
"vendor": ""
}
],
"facts": [
{
"id": "creds",
"surfaces": [
"cli",
"desktop"
],
"q": "Are there credential files in your home directory?",
"hint": "Cloud config, kubeconfig, SSH keys, registry tokens — the usual dotfiles.",
"default": "unsure"
},
{
"id": "cloud",
"surfaces": [
"cli",
"desktop"
],
"requires": [
"creds"
],
"q": "Do any of them open a cloud or cluster account?",
"default": "unsure"
},
{
"id": "codehost",
"surfaces": [
"cli",
"desktop"
],
"requires": [
"creds"
],
"q": "Do any of them push to a code host?",
"default": "unsure"
},
{
"id": "registry",
"surfaces": [
"cli",
"desktop"
],
"requires": [
"creds"
],
"q": "Do any of them publish packages or images?",
"default": "unsure"
},
{
"id": "history",
"surfaces": [
"cli",
"desktop"
],
"q": "Do you keep shell history or previous session transcripts?",
"hint": "A transcript is a superset of every file that session read.",
"default": "yes"
},
{
"id": "exec",
"surfaces": [
"desktop"
],
"q": "Can it run terminal commands for you?",
"hint": "Many desktop apps can, through a tool or an extension.",
"default": "unsure"
},
{
"id": "connectors",
"surfaces": [
"web"
],
"q": "Have you connected it to anything — mail, drive, a code host, an MCP server?",
"default": "unsure"
},
{
"id": "upload",
"surfaces": [
"web"
],
"q": "Do you paste or upload work files into it?",
"default": "yes"
},
{
"id": "repo",
"surfaces": [
"agentbox"
],
"q": "Does it have a repository attached?",
"default": "yes"
},
{
"id": "signing",
"surfaces": [
"agentbox"
],
"q": "Is a commit signing identity configured in it?",
"default": "unsure"
}
],
"controls": [
{
"id": "sep-account",
"surfaces": [
"cli"
],
"label": "It runs under a separate user account",
"effort": "hard — days, and it fights you",
"tier": "boundary",
"removes": [
"creds",
"hist"
],
"note": "The single largest reduction available, and the reason almost nobody does it is that it is genuinely difficult: paths, permissions, agents and editors all assume one account. Desktop applications frequently cannot be run this way at all."
},
{
"id": "container",
"surfaces": [
"cli"
],
"label": "It runs in a container with only the project mounted",
"effort": "an afternoon, then ongoing friction",
"tier": "boundary",
"removes": [
"creds",
"hist"
],
"downgrades": {
"exec": "container"
},
"note": "Execution survives inside the container and stops being execution on your machine. The friction is real and recurring — mounts, tokens, editor integration."
},
{
"id": "egress",
"surfaces": [
"cli",
"desktop",
"agentbox"
],
"label": "Outbound traffic goes through an allowlist",
"effort": "an hour, if you already have somewhere to put it",
"tier": "boundary",
"swaps": {
"net.any": "net.allowed"
},
"note": "The one control the hosted container already has, demonstrated rather than claimed. You can have it too."
},
{
"id": "vault-creds",
"surfaces": [
"cli",
"desktop"
],
"label": "Credentials live somewhere the agent's account cannot open",
"effort": "an afternoon",
"tier": "boundary",
"removes": [
"creds"
],
"note": "Only helps if the agent cannot become you — pair it with a separate account or a container, or it is a setting wearing a boundary's clothes."
},
{
"id": "no-skip",
"surfaces": [
"cli",
"desktop"
],
"label": "Permission prompts are on, with no skip flag set",
"effort": "five minutes",
"tier": "setting",
"marks": {
"cfg": "setting"
},
"note": "Worth doing and it is NOT a boundary: the prompt is enforced by the tool, and this grant can rewrite the file that disables it. Labelled honestly so you are not misled."
},
{
"id": "no-connect",
"surfaces": [
"web"
],
"label": "No connectors are switched on",
"effort": "immediate",
"tier": "boundary",
"removes": [
"connect"
],
"note": "The connector list is the whole of a hosted assistant's reach beyond the conversation. It is enforced by the vendor and it is genuinely outside the session."
},
{
"id": "less-in",
"surfaces": [
"web",
"agentbox"
],
"label": "Only non-sensitive material goes in",
"effort": "immediate, and continuous",
"tier": "expectation",
"note": "The hosted grant reaches what you put in front of it, and that part IS yours. It is an expectation rather than a boundary because nothing enforces it but you, every time."
}
],
"nodes": {
"cli": [
{
"id": "root",
"parent": null,
"label": "Runs as your user account",
"tier": "none",
"evidence": "derived",
"detail": "This is the grant. Everything below is a consequence of it rather than a separate decision — the agent inherits your account, so it inherits your account's reach."
},
{
"id": "conv",
"parent": "root",
"label": "The conversation itself",
"tier": "none",
"evidence": "derived",
"reaches": [
"chat",
"draft",
"explain"
],
"detail": "Everything an agent does starts here, and it is the part nobody thinks of as a grant. It is drawn because a tool that only lists frightening capabilities is measuring its own framing rather than your setup."
},
{
"id": "files",
"parent": "root",
"label": "Read and write anything your account can",
"mechanism": "the tool's own directory restriction",
"tier": "setting",
"evidence": "derived",
"detail": "The folder restriction is enforced by the tool, which runs inside this grant. Anything that can execute as you can step around it — see the escalation edge from “Execute programs as you”."
},
{
"id": "proj",
"parent": "files",
"label": "The project you are working on",
"tier": "none",
"evidence": "derived",
"reaches": [
"read.project",
"write.project"
]
},
{
"id": "creds",
"parent": "files",
"label": "Credential files in your home directory",
"tier": "none",
"evidence": "third-party",
"requires": "creds",
"reaches": [
"read.credentials"
],
"detail": "A published read-only audit tool enumerates exactly this class: key files and their permissions, cloud and cluster credentials, registry tokens, code-host credentials. Nothing stands in the way, because the files are owned by the account the agent runs as."
},
{
"id": "cloud",
"parent": "creds",
"label": "Cloud and cluster accounts",
"tier": "none",
"evidence": "third-party",
"requires": "cloud",
"reaches": [
"cloud.api"
]
},
{
"id": "code",
"parent": "creds",
"label": "Code hosts and signing keys",
"tier": "none",
"evidence": "third-party",
"requires": "codehost",
"reaches": [
"git.push",
"sign.commits"
]
},
{
"id": "pkg",
"parent": "creds",
"label": "Package and image registries",
"tier": "none",
"evidence": "third-party",
"requires": "registry",
"reaches": [
"pkg.publish"
]
},
{
"id": "hist",
"parent": "files",
"label": "Shell history and past transcripts",
"tier": "none",
"evidence": "third-party",
"requires": "history",
"reaches": [
"read.transcripts"
],
"detail": "A session transcript is a superset of every file that session read, so excluding a secret by path does not exclude its contents. Two independent routes reached this conclusion, which is why it is a finding rather than an observation."
},
{
"id": "cfg",
"parent": "files",
"label": "Its own configuration and rules files",
"mechanism": "a permission prompt",
"tier": "setting",
"evidence": "third-party",
"reaches": [
"alter.limits"
],
"detail": "A prompt that a flag in a writable file can disable is an expectation wearing a setting's clothes. The audit tool named below looks for exactly those flags in shell initialisation."
},
{
"id": "exec",
"parent": "root",
"label": "Execute programs as you",
"mechanism": "an approved-tools list",
"tier": "setting",
"evidence": "derived",
"reaches": [
"exec.local"
],
"detail": "This is the node that makes the two settings above cosmetic. It is why the escalation edges exist."
},
{
"id": "net",
"parent": "root",
"label": "Open outbound connections",
"tier": "none",
"evidence": "derived",
"reaches": [
"net.any"
]
}
],
"desktop": [
{
"id": "root",
"parent": null,
"label": "Runs as your user account",
"tier": "none",
"evidence": "derived",
"detail": "A desktop application installed by you runs as you. The difference from the command line is which confirmations are on by default — and a default is a setting."
},
{
"id": "conv",
"parent": "root",
"label": "The conversation itself",
"tier": "none",
"evidence": "derived",
"reaches": [
"chat",
"draft",
"explain"
],
"detail": "Everything an agent does starts here, and it is the part nobody thinks of as a grant. It is drawn because a tool that only lists frightening capabilities is measuring its own framing rather than your setup."
},
{
"id": "files",
"parent": "root",
"label": "Read and write anything your account can",
"mechanism": "a workspace-folder restriction",
"tier": "setting",
"evidence": "derived",
"reaches": [
"read.project",
"write.project"
]
},
{
"id": "creds",
"parent": "files",
"label": "Credential files in your home directory",
"tier": "none",
"evidence": "third-party",
"requires": "creds",
"reaches": [
"read.credentials"
]
},
{
"id": "cloud",
"parent": "creds",
"label": "Cloud and cluster accounts",
"tier": "none",
"evidence": "third-party",
"requires": "cloud",
"reaches": [
"cloud.api"
]
},
{
"id": "code",
"parent": "creds",
"label": "Code hosts and signing keys",
"tier": "none",
"evidence": "third-party",
"requires": "codehost",
"reaches": [
"git.push",
"sign.commits"
]
},
{
"id": "pkg",
"parent": "creds",
"label": "Package and image registries",
"tier": "none",
"evidence": "third-party",
"requires": "registry",
"reaches": [
"pkg.publish"
]
},
{
"id": "hist",
"parent": "files",
"label": "Shell history and past transcripts",
"tier": "none",
"evidence": "third-party",
"requires": "history",
"reaches": [
"read.transcripts"
]
},
{
"id": "cfg",
"parent": "files",
"label": "Its own settings and rules files",
"mechanism": "a confirmation dialog",
"tier": "setting",
"evidence": "derived",
"reaches": [
"alter.limits"
]
},
{
"id": "exec",
"parent": "root",
"label": "Run terminal commands as you",
"mechanism": "a per-command confirmation",
"tier": "setting",
"evidence": "derived",
"requires": "exec",
"reaches": [
"exec.local"
]
},
{
"id": "net",
"parent": "root",
"label": "Open outbound connections",
"tier": "none",
"evidence": "derived",
"reaches": [
"net.any"
]
}
],
"web": [
{
"id": "root",
"parent": null,
"label": "Runs in the vendor's environment",
"mechanism": "it is not your machine",
"tier": "boundary",
"evidence": "derived",
"detail": "This is the one place a hosted surface is structurally better: your filesystem is not reachable, and the boundary is enforced by something entirely outside the session. You also cannot inspect it, change it, or get it attested."
},
{
"id": "conv",
"parent": "root",
"label": "The conversation",
"tier": "none",
"evidence": "derived",
"reaches": [
"chat",
"draft",
"explain"
]
},
{
"id": "paste",
"parent": "root",
"label": "What you paste or upload",
"tier": "none",
"evidence": "derived",
"requires": "upload",
"reaches": [
"read.project"
],
"detail": "This is the part of a hosted grant that is genuinely yours to control, and the only part. Everything you put in is inside the grant for as long as the conversation exists."
},
{
"id": "connect",
"parent": "root",
"label": "Connectors you switched on",
"mechanism": "the connector list",
"tier": "boundary",
"evidence": "derived",
"requires": "connectors",
"reaches": [
"read.home",
"git.push",
"cloud.api"
],
"detail": "A connector moves a hosted assistant from “reaches what you paste” to “reaches an account”. It is enforced by the vendor and it is outside the session, so it is a real boundary — one you set, and one worth re-reading occasionally."
},
{
"id": "home",
"parent": "root",
"label": "Your own machine's files",
"mechanism": "the vendor's environment is not your machine",
"tier": "boundary",
"evidence": "derived"
}
],
"agentbox": [
{
"id": "root",
"parent": null,
"label": "Runs as root inside a vendor container",
"tier": "none",
"evidence": "measured",
"detail": "Measured inside one running session on 20 August 2026. Root inside the container, with passwordless escalation — so there is no internal boundary at all. One vendor, one surface, one date, and the vendor is not named because the point is the taxonomy rather than the grade."
},
{
"id": "repo",
"parent": "root",
"label": "The repository you attached",
"tier": "none",
"evidence": "measured",
"requires": "repo",
"reaches": [
"read.project",
"write.project",
"git.push"
]
},
{
"id": "sign",
"parent": "root",
"label": "A configured commit signing identity",
"tier": "none",
"evidence": "measured",
"requires": "signing",
"reaches": [
"sign.commits"
]
},
{
"id": "home",
"parent": "root",
"label": "Your own machine's files",
"mechanism": "the container is not your machine",
"tier": "boundary",
"evidence": "measured"
},
{
"id": "creds",
"parent": "root",
"label": "Credential stores in the image",
"mechanism": "present, and empty of usable material",
"tier": "boundary",
"evidence": "measured"
},
{
"id": "net",
"parent": "root",
"label": "Outbound network",
"mechanism": "an egress allowlist the process cannot edit",
"tier": "boundary",
"evidence": "tested",
"reaches": [
"net.allowed"
],
"detail": "Probed by making two requests: a package index resolved, an arbitrary public host did not. It is a real boundary for a precise reason — the agent is root, and root cannot defeat it, because nothing inside the container enforces it. This is the only tier-one boundary in the whole library, and it is published because a page that only reports unfavourable findings is doing advocacy rather than measurement."
}
]
},
"escalations": [
{
"surfaces": [
"cli",
"desktop"
],
"from": "exec",
"to": "cfg",
"why": "Anything that can run programs as you can rewrite the file that turns the prompt off."
},
{
"surfaces": [
"cli",
"desktop"
],
"from": "exec",
"to": "creds",
"why": "The folder restriction is enforced by the tool. Execution as you goes around it."
}
],
"capabilities": [
{
"id": "chat",
"group": "benign",
"label": "Have a conversation",
"weight": 0
},
{
"id": "draft",
"group": "benign",
"label": "Draft or edit a document for me",
"weight": 0
},
{
"id": "explain",
"group": "benign",
"label": "Explain code or a file I show it",
"weight": 0
},
{
"id": "read.project",
"group": "work",
"label": "Read the project it is working on",
"weight": 1
},
{
"id": "write.project",
"group": "work",
"label": "Change the project it is working on",
"weight": 1
},
{
"id": "exec.local",
"group": "work",
"label": "Run programs as you",
"weight": 4
},
{
"id": "net.allowed",
"group": "work",
"label": "Reach a permitted list of hosts",
"weight": 1
},
{
"id": "net.any",
"group": "work",
"label": "Reach any host on the internet",
"weight": 3
},
{
"id": "git.push",
"group": "work",
"label": "Push to your code hosts",
"weight": 3
},
{
"id": "sign.commits",
"group": "work",
"label": "Sign commits as you",
"weight": 2
},
{
"id": "pkg.publish",
"group": "work",
"label": "Publish packages and images as you",
"weight": 3
},
{
"id": "cloud.api",
"group": "work",
"label": "Act in your cloud and cluster accounts",
"weight": 4
},
{
"id": "read.home",
"group": "reach",
"label": "Read your other files",
"weight": 3
},
{
"id": "write.home",
"group": "reach",
"label": "Change your other files",
"weight": 3
},
{
"id": "read.credentials",
"group": "reach",
"label": "Read your stored credentials",
"weight": 4
},
{
"id": "read.transcripts",
"group": "reach",
"label": "Read your shell history and past sessions",
"weight": 3
},
{
"id": "alter.limits",
"group": "reach",
"label": "Change its own permission settings",
"weight": 4
}
],
"examples": [
{
"id": "solo-dev",
"label": "A developer on a laptop",
"blurb": "One CLI agent, credentials in the home directory, no containment. The common case, and the one with the widest gap.",
"state": {
"products": [
"claude-code"
],
"facts": {
"creds": "yes",
"cloud": "yes",
"codehost": "yes",
"registry": "no",
"history": "yes"
},
"controls": [],
"intent": [
"chat",
"explain",
"read.project",
"write.project"
]
}
},
{
"id": "careful-dev",
"label": "The same developer, contained",
"blurb": "The same agent, in a container, with an egress allowlist. Shows what the controls actually remove.",
"state": {
"products": [
"claude-code"
],
"facts": {
"creds": "yes",
"cloud": "yes",
"codehost": "yes",
"registry": "no",
"history": "yes"
},
"controls": [
"container",
"egress"
],
"intent": [
"chat",
"explain",
"read.project",
"write.project",
"exec.local"
]
}
},
{
"id": "mixed",
"label": "A team using three surfaces",
"blurb": "A CLI on the laptop, a hosted assistant in the browser, and a hosted agent container. Three shapes, one dashboard.",
"state": {
"products": [
"claude-code",
"chatgpt-web",
"claude-code-web"
],
"facts": {
"creds": "yes",
"cloud": "unsure",
"codehost": "yes",
"registry": "unsure",
"history": "yes",
"connectors": "yes",
"upload": "yes",
"repo": "yes",
"signing": "yes"
},
"controls": [],
"intent": [
"chat",
"draft",
"explain",
"read.project",
"write.project"
]
}
},
{
"id": "hosted-only",
"label": "No local agents at all",
"blurb": "Only a hosted assistant, no connectors. The smallest grant in the library — and the one you can least verify.",
"state": {
"products": [
"claude-web"
],
"facts": {
"connectors": "no",
"upload": "yes"
},
"controls": [
"no-connect"
],
"intent": [
"chat",
"draft",
"explain",
"read.project"
]
}
}
],
"rerun": {
"cli": "Run a published read-only agent-risk audit against your own machine — e.g. github.com/bartek-filipiuk/ai-agent-audit — and compare its modules with the nodes here. It reports path, type, count and a redacted fingerprint, and never leaves your machine.",
"desktop": "The same audit covers a desktop install: what matters is which account the application runs under, and whether it can run commands.",
"web": "Open the connector or integration settings and list what is switched on. That list is the whole of the grant beyond the conversation.",
"agentbox": "Inside a session, check the process identity, look for an attestation device, and probe egress by requesting one expected host and one arbitrary one. Two requests is the whole test."
}
}