# Security Policy

## Supported versions

Security fixes are provided for the latest released version of `pi-dcg`.

## Reporting a vulnerability

Do not open a public issue for a suspected vulnerability. Report privately through the repository maintainer's GitHub security contact. Include a description, reproduction steps, affected versions, and suggested mitigation when available.

## Security model

`pi-dcg` is a local guardrail bridge, not a sandbox or authorization boundary. Pi extensions execute with the same permissions as the user running Pi, and dcg is a separately installed executable with those permissions.

The bridge:

- intercepts Pi's built-in agent `bash` calls, including codemode and other `ctx.executeTool()` calls, and, by default, user `!`/`!!` commands;
- intercepts `exec_command` startup, checks `cmd` in the canonical `workdir`, and freezes all startup arguments after approval;
- starts the configured dcg executable directly without a shell;
- sends command text to that local child process on stdin;
- sets the DCG child cwd to Pi's current working directory for ordinary bash, or the canonical command directory for managed bash and `exec_command`;
- honors managed bash cwd only through a non-serialized capability on the registered executor schema, never through agent-supplied arguments alone; extra `workdir` fields on ordinary bash do not change its policy directory;
- validates dcg's structured stdout decision;
- seals an approved agent `bash` command, freezes all startup arguments (including mode and cwd), and seals its input reference so later `tool_call` handlers cannot change them unchecked; detects argument changes during asynchronous policy checks;
- keeps allow-once commands out of model-visible denial results and shows them only through user-facing UI notifications;
- captures but does not log or forward dcg stderr;
- bounds child output and denial text;
- forwards turn/runtime cancellation to policy checks and confirmation dialogs, blocking even in fail-open mode;
- serializes this extension instance's confirmation dialogs without serializing ordinary policy checks or allowing approvals to carry over to another call;
- preserves hard dcg denials without a one-click bypass.

The child receives Pi's environment because dcg policy is intentionally configured through `DCG_*` variables. `pi-dcg` additionally sets `PI_CODING_AGENT=true`, `DCG_NO_SELF_HEAL=1`, and no-color flags for that child. Environment values are never logged or sent over the network by this package.

### Failure behavior

Bridge failures default to visible fail-open behavior to match dcg's integration philosophy. Set `PI_DCG_ON_ERROR=block` to block when the bridge cannot start dcg, times out, exceeds output limits, receives a nonzero exit, or cannot validate stdout.

This setting cannot detect dcg's internal intentional fail-open paths, which may return a valid allow after size, parse, AST, or deadline fallback. Configure dcg itself for stricter analysis where supported.

Turn abort and runtime shutdown cancel active and queued DCG confirmations. Late UI responses cannot reverse cancellation. Print/JSON sessions without UI block `ask`; RPC clients can answer through the extension UI protocol. This does not extend coverage to RPC control-channel shell commands.

### Host composition limits (Pi 1.4.0)

Command sealing protects against later `tool_call` mutations, not a replacement of the entire input object by an earlier handler. Pi retains the original execution arguments in that case, but DCG sees the replacement. An upstream argument-identity fix is needed before claiming that every possible hook composition executes exactly the checked command. Earlier handlers must mutate argument fields in place.

The confirmation queue is local to one DCG extension instance. Pi 1.4.0 owns
a dialog stack that restores the preceding prompt when the visible prompt
closes. Mixed DCG startup and process-input tests verify restoration and
separate denials. The input-object replacement issue remains on Pi 1.4.0.
No local host patch or approval bypass is authorized.

The real-session tests record these host limitations explicitly. They are not passing safety guarantees. No global fail-open switch, model-callable bypass, executor replacement, new credential flow, or additional command logging is introduced.

### Known bypasses

The extension cannot intercept arbitrary process creation. Important bypasses include:

- custom tools with names other than `bash` or `exec_command`;
- incremental `write_stdin` input (the separate human approval in `pi-processes` is not a DCG safety decision);
- Pi's RPC control-channel `{"type":"bash"}` command, which does not emit a `user_bash` event;
- `pi.exec()` and child processes started inside another extension;
- non-shell file, database, cloud, or API operations;
- opaque generated scripts and dynamic payloads dcg cannot inspect;
- earlier Pi `user_bash` handlers that fully replace execution;
- dcg rules, packs, safe patterns, allowlists, bypass variables, and fail-open analysis behavior.

Use least-privilege credentials, version control, backups, containers/VMs, and OS-level sandboxing when destructive operations must be prevented rather than merely guarded.

## External dcg dependency and license

`pi-dcg` does not bundle or redistribute Destructive Command Guard. Users install it separately and are responsible for reviewing its code, releases, provenance, and nonstandard license, including its OpenAI/Anthropic rider. This package's MIT license does not apply to dcg.

## Telemetry

On startup, `@mocito/install-telemetry` sends a best-effort install/update telemetry ping to the configured telemetry endpoint once per package version unless disabled by CI, `PI_OFFLINE`, `PI_TELEMETRY`, or Pi's `enableInstallTelemetry` setting. The ping includes only package name/version and platform/runtime/architecture. It never includes commands, paths, dcg decisions, stderr, configuration, environment variables, prompts, credentials, or policy.
