Skip to content

ci: rule-file injection check (hidden text, install directives, unknown packages) - #5

Merged
scrimshawlife-ctrl merged 1 commit into
mainfrom
cursor/rule-file-injection-check-7dd5
Oct 19, 2026
Merged

scrimshawlife-ctrl merged 1 commit into
mainfrom
cursor/rule-file-injection-check-7dd5

Conversation

@scrimshawlife-ctrl

Copy link
Copy Markdown
Contributor

Description

Add a dependency-light rule-file injection check. scripts/check-rule-files.py uses the Python standard library only and does not call GitHub Actions. It scans AGENTS.md, CLAUDE.md, .cursorrules, .cursor/rules/**, skills/**/SKILL.md, rules/*.md, and templates/*.template.

  • HIDDEN fails closed and cannot be allowlisted: zero-width characters (U+200B–U+200D, U+2060, U+FEFF), bidi controls (U+202A–U+202E, U+2066–U+2069), HTML comments that contain imperative or install wording, invisible HTML/CSS, and lines over 400 characters.
  • INSTRUCTION flags dependency and install directives: pip / npm / yarn / pnpm / cargo / go with install or add, replace X with, use (the) package, curl piped to sh or bash, wget piped to bash or sh, and --index-url / --extra-index-url / registry= / .npmrc overrides.
  • UNKNOWN_PKG flags package names in those directives that are absent from the repo lockfile or manifest (package.json, npm/yarn/pnpm lockfiles, requirements*.txt, pyproject.toml, go.mod, go.sum, Cargo.toml, Cargo.lock). If the repo has no manifest, those names are reported and do not fail the check.

INSTRUCTION and UNKNOWN_PKG fail unless .rule-file-allowlist matches path, rule, pattern, and reason. Exit 0 is clean. Exit 1 means a finding remains. make check-rule-files runs the scanner and tests/test_rule_file_check.py.

Motivated by arXiv 2610.09264: rule-file prompt injection can make coding agents swap dependencies. This pack’s scanned files have no install directives, so the allowlist is comments only.

Related Issue

No linked issue.

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Local make check-rule-files on commit f93f3665c9175d622f0cfd8f0f20020d1c9f7c76. The command does not use GitHub Actions. Fixture tests cover clean and malicious cases for zero-width text, bidi controls, HTML-comment injection, curl|sh, registry overrides, and package swaps.

Local CI receipt

python3 scripts/check-rule-files.py
rule-file-check
date: 2026-10-19T17:00:03Z
commit: f93f3665c9175d622f0cfd8f0f20020d1c9f7c76
files_scanned: 8
files_passed: 8
files_failed: 0
findings_failed: 0
findings_allowlisted: 0
findings_reported: 0
manifests: 0
result: PASS
unknown_pkg: report-only (no lockfile or manifest)
scanned:
AGENTS.md
rules/zero-state-context.md
skills/zero-state-context/SKILL.md
templates/AGENT-GOTCHAS.md.template
templates/AGENTS.md.template
templates/CLAUDE.md.template
templates/intent.md.template
templates/spec-Workflows-section.md.template
findings:
(none)
python3 -m unittest tests/test_rule_file_check.py
..............
----------------------------------------------------------------------
Ran 14 tests in 2.184s

OK

Pass: 8 rule files, 14 unit tests. Fail: 0.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented on hard-to-understand areas in my code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and updated in downstream documentation.
Open in Web Open in Cursor 

…wn packages)

Scan agent rule files with stdlib Python for hidden text, install
directives, and packages missing from the repo manifest. HIDDEN
findings fail closed. INSTRUCTION and UNKNOWN_PKG honor
.rule-file-allowlist. Wire the check into make and CI.

Co-authored-by: Daniel Meyer <scrimshawlife-ctrl@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

CC @Zero-State-LLC/partner-agents. Flagged for shared triage.

@scrimshawlife-ctrl
scrimshawlife-ctrl marked this pull request as ready for review October 19, 2026 17:03
@scrimshawlife-ctrl
scrimshawlife-ctrl requested a review from a team as a code owner October 19, 2026 17:03
@scrimshawlife-ctrl
scrimshawlife-ctrl merged commit f89de6d into main Oct 19, 2026
2 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T17:05:44.731146Z f93f366 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f93f3665c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +282 to +285
templates = root / "templates"
if templates.is_dir() and not templates.is_symlink():
for path in sorted(templates.glob("*.template")):
consider_file(root, path, files, notes)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject a symlinked templates directory

When templates is a symlink to another checked-in directory, this condition silently skips every template and can still return PASS; the preceding “Require pack files” step in .github/workflows/ci.yml also succeeds when the symlink target contains the required filenames. This leaves hidden text or install directives in those templates completely unscanned, unlike the explicit fail-closed handling already used for .cursor/rules and skills, so the directory itself should produce a HIDDEN failure.

Useful? React with 👍 / 👎.

Comment on lines +437 to +438
for match in re.finditer(r"(?m)^(?:require\s+)?(\S+)\s+v\d", text):
add_name(names, match.group(1))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse dependencies inside Go require blocks

For a valid go.mod using require ( ... ), dependency lines are normally indented, but this regex requires the module path at column 1. In a repository without a populated go.sum, a declared dependency such as github.com/acme/known is therefore absent from known, and an otherwise allowlisted rule-file mention of that package fails CI as UNKNOWN_PKG.

Useful? React with 👍 / 👎.

token = re.split(r"[<>]", token, maxsplit=1)[0].strip()
if not PKG_BODY_RE.fullmatch(token):
return None
return token.casefold()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Canonicalize Python distribution names before comparison

Python distribution names treat runs of -, _, and . equivalently, but norm_pkg only case-folds them. Consequently, with known_pkg==1 in requirements.txt, an allowlisted pip install known-pkg directive still fails as unknown-package: known-pkg, producing false CI failures for common package-name spellings.

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants