Repository navigation
fix(pe3): treat ignore-file entries as path exclusions, not credential access - #787
Merged
Merged
Conversation
…l access PE3 matches credential file names lexically in every file type. In a .gitignore, the entry `.env` under a "secrets" comment matched the bare .env pattern and was reported as HIGH Credential Access. That entry keeps the file out of version control and reads nothing. The existing .env documentation filter only covers Markdown and text, and ignore files infer as "other", so nothing qualified the match. Skip a PE3 match only when all of these hold: - The file is a gitignore-syntax exclusion list: .gitignore, .dockerignore and <Dockerfile>.dockerignore, .npmignore, .helmignore, .gcloudignore, .vercelignore, the ESLint, Prettier and Stylelint ignore files, .ignore, .rgignore, .fdignore, and the Cursor, Gemini and Aider agent ignore files. - The whole physical line, split on "\n" as those parsers split it, is one pattern token that contains the match. - The token is not written as a host location: ~, a drive letter, /etc, /home, /Users, /root, or a ".." segment. Every other case keeps its finding at the old severity: - Comments, which are free text an agent may read as instructions. - Negated entries such as !.env. They re-include the secrets file in the commit, build context, package or agent view that the file governs. - Lines with whitespace, quotes, $ or shell control characters. Unicode separators that the analyzer treats as line breaks count as whitespace. - Lines longer than the 4,096-character classification bound. - The same references in any other file: SKILL.md, scripts, YAML config, plain path lists, and .gitattributes. A .gitattributes line attaches filter, diff and merge drivers to paths; it does not exclude them. Signed-off-by: Narendran Raghavan <nraghavan@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rng1995
commented
Oct 7, 2026
rng1995
left a comment
Collaborator
Author
There was a problem hiding this comment.
Review: the exemption is correctly narrow. The file kind, a single-token line and a non-host path all have to hold, and negations, comments and .gitattributes stay fail-closed. I re-ran the host-path probes against main. One P3 documentation/test nit; otherwise ready.
Any basename ending in .dockerignore selects the ignore-file rules, with or without a matching Dockerfile in the bundle. Say so next to the suffix constant, and note that each exemption still needs a line that is one pattern token, not a negation and not a host path. Pin both directions in notes.dockerignore: a lone .env entry is exempt, while a command or prose line naming .env keeps its PE3 finding. Signed-off-by: Narendran Raghavan <nraghavan@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PE3 (Credential Access) matches credential file names lexically in every file type. A skill's
.gitignorethat lists.envunder a# Environment & secretscomment is therefore reported as HIGH Credential Access, even though that entry keeps the file out of version control and reads nothing. The HIGH blocks downstream signing gates on an otherwise clean skill. It reproduces on 2.11.2, 2.12.0 andmain(3a1ceee).This PR treats a single path pattern on its own line of a gitignore-syntax exclusion file as a path exclusion, not credential access.
Customer impact
Reported internally: an internal skill's release gate fails on
PE3 HIGH .gitignore:2 '.env'on every SkillSpector version. With this PR that single finding disappears. Nothing else in the report changes (30 → 29 issues; all other sections identical apart fromscanned_at).Root cause
static_patterns_privilege_escalation.pymatches the bare.envpattern anywhere.other..envqualifier (_is_env_file_reference_in_docs) applies to Markdown and text.So nothing qualified the match.
Fix
A PE3 match is skipped, in the same way as the existing keyring-noun skip, only when all of these hold:
.gitignore,.dockerignore(and<Dockerfile>.dockerignore),.npmignore,.helmignore,.gcloudignoreor.vercelignore; the ESLint, Prettier or Stylelint ignore file;.ignore,.rgignoreor.fdignore; or the Cursor, Gemini or Aider agent ignore files.\nas those parsers do, with a trailing\rdropped.~, a drive letter,/etc,/home,/Usersor/root, and no..segment.The file name alone never exempts anything. Everything else keeps its finding at the old severity:
!.env. They re-include the secrets file in the commit, build context, package or agent view.$or shell control characters, or longer than the 4,096-character classification bound..gitattributes. Its lines attach filter, diff and merge drivers to paths rather than excluding them..env.Tests
tests/nodes/analyzers/test_pe3_ignore_file_entries.pyadds 85 synthetic tests. The 47 that cover the fix fail onmain; the 38 fail-closed controls pass on both..gitignore;$HOME, host paths, Unicode separators and overlong lines;.gitattributes;.envreads in Python, shell, SKILL.md and YAML.!.env.localand on the script that reads.env.make lintandmake format-checkpass. The unit suite (pytest -m "not integration and not provider" tests/) gives 10502 passed, 15 skipped, 4 xfailed, 0 failed.Residual
.gitattributeslines such as.env filter=git-cryptstill raise PE3. That is a separate false positive, left out of scope.🤖 Generated with Claude Code