Security
PiG runs with the permissions of the user who starts it. PiG is not a security sandbox for model output, tools, extensions, skills, hooks, or shell commands.
Use a container, virtual machine, or another operating-system boundary when you need isolation.
Project trust
A repository can contain project settings and Resources that change PiG behavior. PiG requires a trust decision before it loads project-controlled executable or configuration input.
Project trust is not a complete startup boundary. As in Pi, PiG reads the project sessionDir setting while it selects or creates a session, before it resolves project trust. Project trust also does not limit what tool calls can access: enabled tools use the operating-system permissions of the PiG process.
Trust-sensitive project paths include:
.pig/settings.json
.pig/mcp.json
.pig/extensions/
.pig/skills/
.pig/prompts/
.pig/themes/
.pig/SYSTEM.md
.pig/APPEND_SYSTEM.md
.agents/skills/A bare .pig directory does not require project trust. Context files such as AGENTS.override.md, AGENTS.md and CLAUDE.md load whatever the trust decision is, unless you disable context loading. Treat instructions in a folder as untrusted input even when you decline project trust.
A Piglet in .pig/piglets/ is also project input. --piglet <name> uses it only with a saved trust decision, defaultProjectTrust: "always" or --approve, and a bare name is never read from the working directory.
PiG chooses a trust decision as Pi does:
- A command-line
--approveor--no-approveapplies first. - User-level and command-line extensions can handle the
project_trustevent. The first extension that returns yes or no owns the decision. - Otherwise PiG uses the saved decision for the current directory or its closest parent. Decisions are stored by canonical directory in
~/.pig/agent/trust.json. - Otherwise PiG follows the global
defaultProjectTrustsetting, whose default is"ask".
Print, JSON and RPC modes cannot show the trust prompt. Without an override, extension or saved decision, defaultProjectTrust: "always" loads the protected project files, and "ask" or "never" skips them.
Use /trust to manage the current project decision. The selector shows the saved decision and the current session's trust state separately. A checkmark stays on the saved choice while you browse. Select Trust parent folder to trust the parent and clear the current project's override. Restart PiG after changing trust so startup discovery runs under the new decision.
Project trust explains each step of the decision and compares it with Pi.
Sessions and credentials
Sessions can contain prompts, tool arguments, command output, file contents and credentials that appeared in the conversation. Review a session before you export or share it.
PiG creates the agent directory, the sessions directory and each project's session directory with mode 0700 when it creates them. Pi creates them with the umask default, usually 0755 (D132, Pi #10770). A directory that already exists keeps its mode. auth.json is created owner-only (mode 0600 on POSIX, an owner-only DACL on Windows, D68).
The mode 0700 protects only a directory that PiG creates. Session files are created with mode 0644, and trust.json is written with mode 0644. On a shared machine, rely on the mode of the parent directory or on a separate account.
Extensions
Extensions execute code. A subprocess boundary can isolate crashes and support cancellation, but it is not a permission sandbox.
Before you load an extension:
- verify its source and origin;
- review its dependencies;
- inspect required commands and network access;
- understand which files and secrets it can read;
- prefer a constrained operating-system environment for untrusted code.
A fused extension shares the PiG process. Review fused code more strictly because a panic, deadlock, or resource leak can affect the whole agent application.
Packages
A Package can distribute executable extensions and instruction Resources. Installing a Package can make those Resources available to normal discovery.
Review Package membership before installation:
pig package validate ./packageValidate extension behavior without changing settings:
pig install ./extension --validate-only --jsonPackage installation never activates a Piglet. A Piglet separately selects an agent application.
Piglets
Stock PiG has the same security boundary as Pi. It runs as the user, and it has no sandbox. A Piglet does not change that. A Piglet is a declaration, and stock PiG applies it as a narrowing of tools and discovery.
Use exact tool lists and empty discovery lists when an application must not inherit ambient Resources:
tools: [read, grep, find]
discovery:
extensions: []
skills: []Command-line options can narrow a Piglet. They cannot widen it. An overlay that widens tools, discovery, agentEnv, the tools of an extension it names again, or removes a strip entry needs extends.allowWiden: true. An overlay can add a new extension without it.
A Piglet Binary adds guarantees that stock PiG does not give. The next section lists them. It also lists what a Piglet Binary does not guarantee.
What a Piglet Binary guarantees
The guarantees below hold for a Piglet Binary built with build.closed: true. A Binary is open by default. It behaves as stock PiG started with its Piglet: it accepts an overlay Piglet, --system-prompt and ambient Resources that its effective Piglet's discovery allows. Organizations opt in to the closed Binary. Build a controlled deployment with build.closed: true.
Fused extensions. A fused extension is compiled into the executable. The Binary starts it in the PiG process. It does not build, download, or run a subprocess for it. A fused extension that fails to load is reported and is not replaced by a subprocess. At startup the Binary checks that the fused extensions equal the component plan it was built with. It exits when they differ.
No Piglet or ambient Resource selection at run time. A closed Binary refuses --piglet, PIG_PIGLET_PATH, PIG_PIGLET_NAME and --system-prompt, and each refusal names build.closed. It loads no ambient extension or skill, even when its Piglet lists a discovery scope.
No extension or MCP server added at run time. A closed Binary refuses -e/--extension (a path, npm: or git: source), pig install, pig remove, pig update --extensions and pig mcp add, and each refusal names the option, the Binary and build.closed. It ignores settings.extensions and the servers of the user and project mcp.json, and reports a notice. Only what its signed closure lists runs; an extension in the closure can still register MCP servers.
A fixed set of fused and packed extensions. At startup the Binary checks that the fused and packed extensions that start have the names its component plan lists, no more and no fewer. This is a check of names. It does not pin PATH for tools or runtimes. Startup does not install a Package or download a component.
Tool ceilings. The tools list of a Piglet, and the tools list of an extension entry, are a ceiling. The session tool registry admits a tool only when the ceiling, --tools and --exclude-tools all admit it. A tool outside the ceiling is not listed, is not active, and is not reachable by codemode or tool_search. A later setActiveTools call, a late registration, or a reload cannot bring it back. The ceiling does not filter the arguments, paths or output of a tool that it admits. A Piglet with no extensions: section keeps every MCP tool, and a tool of an extension that the Piglet does not name is kept.
Strips that overlays cannot undo. A strip entry marked stripped(binary) names code that a build tag left out of the executable. An overlay cannot re-enable it, with or without extends.allowWiden. The strip list is part of the Binary record digest.
Signed Binaries. A Binary built with --sign-key carries an Ed25519 signature in a DSSE envelope. At every start the Binary verifies the signature offline. It refuses to run when the executable, the manifest, or the signature changed. With pig piglet trust require on, a Binary without a signature from a locally trusted key does not run, and pig piglet pull does not install it. pig piglet pull also verifies the DSSE release index and pins the first signer of each Piglet.
A container for the agent, when the Piglet declares one. A source Piglet with agentEnv.image and pigRuntime.mode: image runs pig in a container. The container runs as the invoking user with all capabilities dropped, no-new-privileges, a read-only root file system and limits on memory, CPU and processes. It does not receive the host environment. It receives only the secrets that agentEnv.secrets binds with a declared secretRef, and the fixed PIG_* variables that the launch sets. If the environment cannot start, PiG does not fall back to the host.
What a Piglet Binary does not guarantee
- It is not a sandbox. A Binary runs as the user. The fused code shares the PiG process. The model can still run the tools that the ceiling leaves.
- An open Binary does not stop
-e,pig installor MCP configuration. An open Binary loads an extension that the user names with-e(a path,npm:orgit:source), accepts the package commands, and loads the MCP servers of the user configuration and of a trusted project, as stock PiG does. Only a closed Binary (build.closed: true) refuses them. Stripmcpto remove MCP from a Binary of either kind. - It does not pin
PATHor runtimes. Thebashtool, MCP servers and extensions find programs through the inheritedPATH. A Node extension runs thenodefound onPATH. A Python or Lisp source extension findsuv, Python or SBCL onPATH. - The signature is a self-check. A signature proves that the file is unchanged since a key signed it. A person who can rewrite the Binary and the trust store can sign a replacement. An unsigned Binary runs unless
trust requireis on. - Revocation is local.
pig piglet trust revokechanges a file on one machine. There is no revocation list, no key expiry and no online check. Distribute therevokedfile with your configuration tool. - Builds are not locked.
pig piglet build --lockedand--recordfail with "not implemented". A Binary record holds digests, andpig piglet verify --sourcechecks them. - The
agentEnvcontainer is not available for a Binary.pig piglet buildrefuses a Piglet withagentEnv. The container runs only for a source Piglet that names an image. The--unsafe-hostoption skips the container and prints a warning. The container network is the default bridge network, and no setting limits it. A command that thebashtool runs inherits the container environment, including the bound secrets.
What needs the planned Piglet Image
A Piglet Image is planned and is not built today. pig piglet build --format image fails with Piglet Image build is not implemented. These need it:
- a Binary that carries its own
agentEnvand starts inside it; - the Dev Container and materialized source forms of
agentEnv; pigRuntimemodes other thanimage, andagentEnvtogether withextends;- secret file targets;
- an environment that one signed artifact fixes, so that the host cannot swap the image.
Until then, a container or virtual machine around the Binary, a network policy and a pinned image stay your job.
Secrets
Keep secret values outside portable Piglet source, Package metadata, records, sessions, logs, command arguments, and image layers.
Use environment, owner-only files, or contributed secret resolvers. PiG validates declarations and fails before startup when a required value is missing or unauthorized.
Do not put credentials in:
- a Piglet YAML file;
- an extension source archive;
- a prompt or skill;
- a website example;
- a generated Binary record.
Model providers
Provider credentials can grant access to paid services and private data. Use the provider's documented environment variable or PiG login store. Do not copy tokens into repository settings.
Treat model output as untrusted input. A model can propose a harmful command even when the provider connection is trusted.
Connection failure
PiG detects extension transport and heartbeat failures within bounded lifecycle rules. It cancels owned pending calls, closes connection-owned UI state, and isolates or quarantines the affected extension or cell.
PiG does not replay an interrupted operation automatically. Automatic replay could duplicate file, shell, network, message, or transaction effects.
See Extensions.
Distrusted certificate authorities
PiG's own HTTPS and WebSocket connections (model providers, OAuth, MCP, package and tool downloads, self-update) refuse a certificate chain that includes one of eight eMudhra intermediate CAs or one of three roots. The private keys of the eight intermediates can be recovered by anyone from their public certificates (Mozilla bug 2083449, October 2026); Sectigo cross-signed the same keys, and Apple and Microsoft still trust that root. The three roots are the ones Mozilla removed from NSS 3.131.1: emSign ECC Root CA - G3, emSign Root CA - C1 and emSign ECC Root CA - C3.
The check compares public-key digests, so it also refuses the cross-signed certificates, and it runs on top of the operating system's trust store, which can keep trusting these CAs until its vendor updates. When PiG's check refuses a chain, the error names the server and the CA. Go 1.27.3's own verifier, which PiG's pinned toolchain carries, already refuses the eight intermediates with x509: no valid chains built; PiG's check adds the three roots and covers a build with an older Go. No setting turns it off; a connection made with a provider's opt-in insecure option skips verification altogether, so it has no verified chain to check. The connections that extension processes open themselves use that runtime's trust store: run Node.js 22.23.4, 24.22.1, 26.12.1 or later, which carry the same distrust.
Piglet Binary verification
A Piglet Binary verifies its embedded Piglet and component plan before command dispatch. A Binary built with --sign-key also verifies its Ed25519 signature offline and refuses to run when its executable, manifest, or signature changed. When its file is unchanged since its last passing start, it skips the hash of its executable bytes. See Verification cache for what that keeps and gives up. The startup check is a self-check: it does not stop an attacker who can rewrite the Binary.
Use pig verify <binary> to report the signature status without running the Binary. Use pig piglet trust add <key.pub> to trust a reviewed publisher key, pig piglet trust revoke <key-id> to reject it, and pig piglet trust require on to require signatures by locally trusted keys. An embedded author key proves continuity from that key, not the human identity of its holder.
A Sigstore keyless attestation is separate build-provenance evidence. pig verify --provenance --repo <owner/name> --signer-workflow <workflow> <binary> delegates to gh attestation verify and may contact GitHub. Startup never makes that network request.
It does not silently install, download, substitute, or weaken missing requirements. Verify the release checksum, offline signature, and available provenance before execution.
A Binary can still require external services, configuration, runtimes, and secrets. Read its record instead of assuming that one file is self-contained.
Enterprise deployment
An enterprise review asks for a set of controls. This table maps each to a Piglet setting. A row that says "No setting" has no control in PiG today. Provide that control outside PiG.
Control | Piglet setting | What it gives | Limit |
| C1: run untrusted tools and extensions inside an operating-system boundary, with a low-privilege account | agentEnv.image with pigRuntime.mode: image, on a source Piglet. For a Binary, run it in a container or virtual machine that you provide. | The agent runs in a container as the invoking user, with no capabilities, no new privileges and a read-only root file system. | Not available inside a Binary. --unsafe-host skips it. The network is not restricted. |
| C2a: run model-chosen commands as an argument array, never through a shell | tools without bash or powershell, or strip.tools. | The model has no shell tool. | No setting makes the bash tool use an argument array. It always runs shell -c <command>. |
| C2b: allow only listed commands and arguments | No setting. | None. Omit bash as above, and give the model a fused extension tool that runs only the commands you accept. | A fused extension tool is code you review. PiG does not check it. |
| C3a: children get a minimal environment and a secrets broker | agentEnv.secrets with secretRef, and secrets declarations. | The container receives only the bound secrets, not the host environment. | A command that the bash tool runs inherits the whole container environment. No per-tool filter or broker exists. |
C3b: pin an absolute PATH | No setting. | None. Set PATH in the image. | Node, Python and Lisp source extensions find their runtimes on PATH. |
Build a controlled Binary in these steps:
- Set an exact
toolslist, and setdiscovery.extensions: []anddiscovery.skills: []. - Strip the built-ins that the application does not need, with
strip. - Set
build.closed: true, and addmcptostrip.extensionswhen the application needs no MCP server. - Build with
--sign-key. Runpig piglet trust addfor the publisher key, and runpig piglet trust require onon each host. - Run the Binary in a container or virtual machine that you provide, with the secrets injected at run time. The closed Binary refuses
-e, the package commands and MCP configuration, so the command line cannot add code. The Binary fixes what it ships, and the container fixes what it can reach. - Run
pig verify <binary>andpig piglet verify <binary> --source <piglet.yaml>before you release it. The second command fails when the source differs from the baked Piglet, which includes a source that turnsbuild.closedoff.
An open Binary refuses nothing for --piglet. A closed Binary refuses --piglet with a message that names build.closed. Use that message to test a build.
Network content
The documentation site's package and model catalogs contain third-party metadata. A listing does not prove PiG compatibility, security, or endorsement.
Review the publisher, license, source, and integrity evidence before use.
Report a vulnerability
Do not open a public issue for an undisclosed vulnerability. Follow the private reporting instructions in the repository's .github/SECURITY.md. Do not publish exploit details.