Summary
environment_without_credentials() (in code_puppy/provider_credentials.py) currently scrubs child-process/hook environments using a denylist of known code-puppy provider credentials — the well-known provider keys plus whatever $ENV names are referenced in the user's configured models.json. Everything else in the environment passes through unchanged to spawned shell commands and hooks.
This is a real improvement over the previous suffix-based denylist (_API_KEY/_TOKEN/_SECRET), which broke legitimate tooling like GITHUB_TOKEN/NPM_TOKEN while still missing plenty of comparably sensitive vars (DATABASE_URL, SSH_*, etc.) — see #790.
The gap
Any secret-shaped env var that isn't a code-puppy provider credential (STRIPE_API_KEY, an internal SLACK_TOKEN, a DATABASE_URL with embedded creds, a corporate SSO token sitting in the user's shell) now flows straight through to every child process the agent spawns. Since code-puppy already executes arbitrary LLM-directed shell commands and hooks, this is a real — if narrow, and gated behind an adversarial precondition like prompt injection — exfiltration surface.
This didn't block #790 (the new model is strictly better than what it replaced), but it's worth its own design discussion per the review thread there.
Proposed direction
Flip the model from denylist to allowlist: "only these names are permitted to reach children" (PATH, HOME, locale vars, well-understood dev-tool tokens like GITHUB_TOKEN/NPM_TOKEN/AWS_*, proxy settings, etc.) instead of "block everything we recognize as code-puppy's own."
This needs discussion before implementation — too narrow an allowlist breaks real workflows (corporate proxies, custom CI vars, hook-specific env needs) that are hard to fully anticipate up front. Opening this issue to track that discussion rather than proposing a specific list unilaterally.
Context
Surfaced during review of #790. Internal tracking: PUP-640.
Summary
environment_without_credentials()(incode_puppy/provider_credentials.py) currently scrubs child-process/hook environments using a denylist of known code-puppy provider credentials — the well-known provider keys plus whatever$ENVnames are referenced in the user's configuredmodels.json. Everything else in the environment passes through unchanged to spawned shell commands and hooks.This is a real improvement over the previous suffix-based denylist (
_API_KEY/_TOKEN/_SECRET), which broke legitimate tooling likeGITHUB_TOKEN/NPM_TOKENwhile still missing plenty of comparably sensitive vars (DATABASE_URL,SSH_*, etc.) — see #790.The gap
Any secret-shaped env var that isn't a code-puppy provider credential (
STRIPE_API_KEY, an internalSLACK_TOKEN, aDATABASE_URLwith embedded creds, a corporate SSO token sitting in the user's shell) now flows straight through to every child process the agent spawns. Since code-puppy already executes arbitrary LLM-directed shell commands and hooks, this is a real — if narrow, and gated behind an adversarial precondition like prompt injection — exfiltration surface.This didn't block #790 (the new model is strictly better than what it replaced), but it's worth its own design discussion per the review thread there.
Proposed direction
Flip the model from denylist to allowlist: "only these names are permitted to reach children" (
PATH,HOME, locale vars, well-understood dev-tool tokens likeGITHUB_TOKEN/NPM_TOKEN/AWS_*, proxy settings, etc.) instead of "block everything we recognize as code-puppy's own."This needs discussion before implementation — too narrow an allowlist breaks real workflows (corporate proxies, custom CI vars, hook-specific env needs) that are hard to fully anticipate up front. Opening this issue to track that discussion rather than proposing a specific list unilaterally.
Context
Surfaced during review of #790. Internal tracking: PUP-640.