Skip to content

E2 shell arm matches one env | grep spelling: a second grep flag, quotes, or egrep all evade "Env Variable Harvesting" #482

Description

@MandoCodes1

Summary

Rule E2 (Data Exfiltration / Env Variable Harvesting) has a shell arm for env | grep, but it accepts exactly one flag (-i) followed by a bare keyword. A second flag, combined flags, a quoted pattern, or egrep all evade it. The README defines E2 as "enumerating, copying, or searching environment data to collect secrets"; the missed spellings are the searching case.

#329 and #441 cover the Python os.environ path. This is the shell path and is independent of both.

Environment

  • SkillSpector v2.11.0 (commit 7805bb9), installed with uv tool install git+https://github.com/NVIDIA/skillspector.git
  • skillspector scan <dir> --no-llm --format json (static-only, deterministic)
  • macOS 15 (Darwin 25.6.0), Python 3.13 runtime

Reproduction

One SKILL.md with one fenced bash block. Only the marked line varies between runs.

spelling E2 fires
env | grep secret yes, 0.8
env | grep -i -E 'token|key|secret' > /tmp/ctx.txt no
env | grep -iE "aws_|secret" no
env | grep --ignore-case token no
env | egrep -e password -e token no
printenv | grep -i secret yes, but only because the line contains the substring env | grep -i secret

The second row is the shape a harvester would write: case-insensitive, alternation over several names, redirected to a file for a later upload. In a skill that goes on to POST that file, the scan reports E1, E3, PE3 and SC2 on the surrounding lines and nothing on the harvest line itself.

Cause

src/skillspector/nodes/analyzers/static_patterns_data_exfiltration.py:73:

(r"env\s*\|\s*grep\s+(?:-i\s+)?(?:key|secret|token|password)", 0.8),

(?:-i\s+)? consumes one -i and nothing else, and the keyword has to follow as a bare word, so a quote or a second flag ends the match. Nothing in tests/unit/test_patterns.py pins a shell spelling; the E2 cases there (lines 150-255) are all Python.

Expected behavior

The shell arm should key on the behavior (the environment piped through a filter for secret-looking names) rather than on one flag layout: env or printenv as the source, grep, egrep or fgrep as the filter, any flags, optional quoting, and the keyword anywhere in the pattern argument. env | grep PATH and env | grep -v SECRET should still pass.

I have a fix with tests and a fixture ready to open against this issue.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions