Skip to content

Tier-1 gate bypass: has_bash_write_pattern exempts all of 2>, so a truncating redirect classifies as read-only #78

Open

Description

@DimitriGeelen

Summary

has_bash_write_pattern (agents/context/lib/safe-commands.sh:1027) uses:

if echo "$cmd" | grep -qE '[^2>&]>[^>&]|>>'; then

The leading class [^2>&] was evidently meant to exempt the fd-dup idiom 2>&1. It does that —
but it exempts every redirect whose > is preceded by 2, including 2> FILE, which
truncates a real file. The command then reports no-write, and with is_bash_safe_command
also returning safe it passes the Tier-1 active-task gate: a file-truncating write allowed with
no active task.

Repro — measured on bleeding-edge (VERSION 1.7.97), not on a fork

COMMAND                            SAFE      WRITE-PATTERN
bin/fw audit > out.txt             SAFE      WRITE        <- correct
bin/fw audit 2> out.txt            SAFE      no-write     <- BYPASS
bin/fw audit &> out.txt            BLOCKED   no-write     <- see note
bin/fw audit 2>&1                  SAFE      no-write     <- correct
bin/fw audit >> out.txt            SAFE      WRITE        <- correct

Reproduce by sourcing the file and calling both predicates on each string.

Note on &>: it comes back BLOCKED, but not because the write was detected — the write
regex misses it identically. It is blocked by the & separator rule. So the same regex defect is
present for &> and merely masked by an unrelated layer. Fixing the separator rule alone would
expose it.

Why it survived

2>&1 and 2> file differ only after the >, but the exemption is written before it. The
character class tests the wrong side of the operator, so it cannot distinguish a dup from a
truncate. Both the intended exemption and the bypass follow from the same expression.

Suggested direction

Exempt the fd-dup form (a & after the operator), not the fd digit before it — something
of the shape "optional leading fd, > or >>, not followed by &". I have deliberately not
opened a PR: this is a security predicate inside a 74KB file with an extensive bats suite, and the
right fix should land with your own regression cases rather than my guess at them. Happy to open
one if you would like it.

Adjacent, same file, same line

That line is echo "$cmd" | grep -qE .... The producer-into-grep -q shape is the one your own
T-2518 comment in agents/fabric/lib/drift.sh documents as SIGPIPE-prone under
set -euo pipefail — grep -q short-circuits, echo takes SIGPIPE, pipefail surfaces 141.
Here a spurious 141 would read as "no write pattern", failing open on a security predicate.
Not observed firing (the input is short), but it is the same class and worth the herestring.

Provenance

Found while fixing the newline/&/|&/;; segmentation bypass reported in #75 — which
bleeding-edge already fixes independently via T-3223, more thoroughly than the downstream fix
did. This one is still live there.

Activity

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions