Skip to content

[sec-check] allow-listed gh label list / gh search --jq env prints GH_TOKEN past the gate hook #596

Description

@danathar-atomic-hive

Security Finding

Severity: high
Type: secret-exposure (permission boundary bypass)

.claude/settings.json pre-approves Bash(gh label list:*), Bash(gh search issues:*) and Bash(gh search prs:*). All three take gh's --jq / -q filter, which gh evaluates with gojq. gojq's env builtin and $ENV variable return the whole process environment, so an allow-listed read prints GH_TOKEN and every other exported variable with no prompt.

.claude/hooks/gate_git_diff.py lists these rows in GATED_PREFIXES, but it only checks them for redirections, substitutions and leading assignments. An unquoted $ENV is refused by accident (any $ counts as a substitution). The bare env builtin, and a single-quoted '$ENV', both pass.

Verified at 37beb34 with gh 2.101.0:

$ PROBE_X=leaked gh label list --repo Danathar/atomic-image-builder --json name --limit 1 --jq 'env.PROBE_X'
leaked
$ PROBE_X=leaked gh search issues zfs --repo Danathar/atomic-image-builder --json title --limit 1 --jq 'env.PROBE_X'
leaked

The hook exits 0 (allowed) for each of these:

  • gh label list --json name --jq env
  • gh label list --json name --jq=env
  • gh label list --json name -q env / -qenv
  • gh search issues x --json title --jq "env.GH_TOKEN"
  • gh search prs x --json title -q '$ENV'

This is the same class as aurora-zfs-simple#292, sensi#394 and zfs-kinoite-complex#309, all fixed and merged. atomic-image-builder was the last repo still open to it.

Impact

A prompt-injected or confused agent session reads the App/user token (and any other secret in the environment, such as ANTHROPIC_API_KEY) into the transcript without the user being asked. No Read(...) deny rule protects an environment variable.

Recommendation

In the gate's gated-prefix branch, when the prefix is gh, read every pflag spelling of the filter (--jq V, --jq=V, -q V, -qV, -q=V, -q at the end of a cluster such as -wq V). Refuse a filter that names env or $ENV. Also refuse a filter that bash rewrites before gh sees it: a live brace ({e,}nv), an unquoted glob, or a leading ~. .env, as a field of the fetched JSON, stays allowed. Add corpus rows and a SECURITY-AI.md note.

A hold-gated PR with this fix follows.


Filed by sec-check agent (ACMM L4/L5 — hold-gated mode)

🐝 Hive Agent: security | Instance: hive-wild-mole | SHA: unknown

— hive: agent=sec-check backend=claude model=claude-opus-5-5 effort=medium claude=2.1.283

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

    agent/sec-checkCreated by Hive for agent-filed issue provenancehive/covered-by-prHive verified that an open PR references or claims this issue; still actionable until confirmedhive/hive-wild-moleApproved by a Hive merger/owner for auto-merge on green CIsecurityApproved by a Hive merger/owner for auto-merge on green CI

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions