# Risk map — earendil-works/pi

> Canonical page: https://codevetter.com/unpack/pi/risk-map

# Risk map — earendil-works/pi

Scanned commit 95fbc04997eaee961eb673fa7923e9220609ebd5 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The dominant risk is intentional: pi is an unsandboxed local agent whose bash/edit/write tools and jiti-loaded extensions run with full user privileges — the docs state this plainly and point to containerization instead. Concrete hotspots: auth.json holds plaintext credentials (mitigated by 0600 + locking); the extension/package system executes third-party code gated only by project trust for project-local sources; RPC/protocol layers have no peer authentication; and giant files (agent-session.ts 4023 lines, interactive-mode.ts 6851 lines, package-manager.ts 2699 lines) concentrate blast radius.
- No built-in sandbox: docs/security.md states built-in tools can read/write files and run shell commands with the pi process's permissions, and extensions run with the same permissions — isolation is delegated to containers/VMs (docs/containerization.md). — [packages/coding-agent/docs/security.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/docs/security.md) [README.md#L40-48](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/README.md#L40-L48)
- auth.json stores OAuth/API credentials in plaintext JSON under ~/.pi/agent; writes use mode 0600 and a proper-lockfile lock, but any process running as the user (including extensions and bash commands) can read it. — [packages/coding-agent/src/core/auth-storage.ts#L25-66](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/auth-storage.ts#L25-L66) [packages/coding-agent/src/config.ts#L548](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/config.ts#L548)
- Extension loader uses jiti to execute arbitrary TypeScript from user dirs, project dirs, npm/git packages, and -e flags; aliases map @earendil-works/*, legacy @mariozechner/* names, and typebox into the host's own modules — so extensions share the host process and its privileges entirely. — [packages/coding-agent/src/core/extensions/loader.ts#L45-121](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/extensions/loader.ts#L45-L121) [packages/coding-agent/src/core/extensions/loader.ts#L1-17](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/extensions/loader.ts#L1-L17)
- Project trust is the only input-loading guard: .pi/settings.json, .pi/{extensions,skills,prompts,themes}, .pi/SYSTEM.md, and .agents/skills require trust before loading; non-interactive modes never prompt, so defaultProjectTrust 'ask'/'never' skips them — meaning a config mistake can silently auto-trust or a repo's context files (AGENTS.md/CLAUDE.md) always load regardless. — [packages/coding-agent/docs/security.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/docs/security.md) [packages/coding-agent/src/main.ts#L704-762](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/main.ts#L704-L762) [packages/coding-agent/src/core/trust-manager.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/trust-manager.ts)
- The bash tool spawns real shells with detached process groups and tracks detached PIDs for killProcessTree; shellCommandPrefix and custom shellPath settings let projects/users alter every command — a footgun if a trusted-but-malicious project sets them. — [packages/coding-agent/src/core/tools/bash.ts#L81-120](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/tools/bash.ts#L81-L120) [packages/coding-agent/src/core/settings-manager.ts#L126-129](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/settings-manager.ts#L126-L129)
- Package manager installs npm/git sources into the agent dir and can self-update the pi binary (with Windows quarantine handling); supply-chain mitigations exist (exact-pinned direct deps, min-release-age=2, npm-shrinkwrap for the published CLI, lifecycle-script allowlist in shrinkwrap generation) but the installed packages still execute as the user. — [packages/coding-agent/src/core/package-manager.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/package-manager.ts) [packages/coding-agent/npm-shrinkwrap.json](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/npm-shrinkwrap.json) [README.md#L78-90](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/README.md#L78-L90) [scripts/generate-coding-agent-shrinkwrap.mjs](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/scripts/generate-coding-agent-shrinkwrap.mjs)
- RPC mode exposes full session control (bash, prompt, fork, switch_session) on stdin/stdout with no authentication — it trusts whoever spawned it; the experimental pi-protocol README explicitly states peer authentication is not implemented by the transport. — [packages/coding-agent/src/modes/rpc/rpc-types.ts#L55-56](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/modes/rpc/rpc-types.ts#L55-L56) [packages/protocol/README.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/protocol/README.md)
- Blast-radius hotspots: agent-session.ts (4023 lines) mixes session lifecycle, extension dispatch, compaction, retry, bash, export; interactive-mode.ts (6851 lines) is the entire TUI; package-manager.ts (2699 lines) does network + fs + spawn — regressions in these files affect every mode. (inferred) — [packages/coding-agent/src/core/agent-session.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/agent-session.ts) [packages/coding-agent/src/modes/interactive/interactive-mode.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/modes/interactive/interactive-mode.ts) [packages/coding-agent/src/core/package-manager.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/core/package-manager.ts)
- Truncated tool calls are a real corruption vector deliberately mitigated: when stopReason is 'length', all tool calls are failed with a re-issue error rather than executed, because the JSON salvage parser can produce arguments that validate but are silently incomplete. — [packages/agent/src/agent-loop.ts#L262-277](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent-loop.ts#L262-L277) [packages/agent/src/agent-loop.ts#L468-500](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/agent/src/agent-loop.ts#L468-L500)
- main() calls process.exit() deep inside helper flows (validateForkFlags, createSessionManager error paths, handlePackageCommand) which complicates embedding and can skip cleanup; a comment notes Windows requires natural drain after `pi update` due to a Node fetch() teardown bug. — [packages/coding-agent/src/main.ts#L298-335](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/main.ts#L298-L335) [packages/coding-agent/src/main.ts#L590-601](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/coding-agent/src/main.ts#L590-L601)
- models.generated.ts and image-models.generated.ts are machine-generated from live provider catalogs; editing them directly is forbidden — regeneration can pull unrelated upstream metadata changes into a diff, which is explicitly accepted. — [AGENTS.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/AGENTS.md) [packages/ai/scripts/generate-models.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/ai/scripts/generate-models.ts) [packages/ai/src/models.generated.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/ai/src/models.generated.ts)
- Git safety rules exist because concurrent pi sessions work in one repo: AGENTS.md forbids git add -A, reset --hard, stash, clean -fd, and --no-verify; the pre-commit hook additionally blocks lockfile changes without PI_ALLOW_LOCKFILE_CHANGE=1. — [AGENTS.md](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/AGENTS.md) [.husky/pre-commit](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/.husky/pre-commit) [scripts/check-lockfile-commit.mjs](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/scripts/check-lockfile-commit.mjs)
- Provider streaming code paths (api/*.ts, ~1.7k-line openai-completions.ts, bedrock-converse-stream.ts) are largely exercised only when real API keys exist, so provider-specific regressions can slip past CI which runs without keys. (inferred) — [packages/ai/src/api/openai-completions.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/ai/src/api/openai-completions.ts) [packages/ai/src/api/bedrock-converse-stream.ts](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/packages/ai/src/api/bedrock-converse-stream.ts) [test.sh](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/test.sh) [.github/workflows/ci.yml](https://github.com/earendil-works/pi/blob/95fbc04997eaee961eb673fa7923e9220609ebd5/.github/workflows/ci.yml)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
