Repository navigation
Conversation
…Sub-Rosa-Issue#480) Known repository malware families keep stable marker strings even when they rename files, but nothing in the repo looked for them. Add a dependency-free, text-only scanner over tracked source and configuration files that reports the marker name, path and line number and never evaluates what it reads, with positive and negative tests, excluded fixtures, and a CI job that runs it on every push and pull request. Closes Sub-Rosa-Issue#480 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.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
Closes #480.
Known repository malware families keep stable marker strings even when they
rename files, but nothing in this repo looked for them. This PR adds a tiny,
dependency-free, text-only marker scanner over tracked source and
configuration files, runs it in CI on every push to
mainand every pullrequest, and documents how to maintain the marker list.
No production code, contract, or dependency is touched.
Acceptance criteria
rmcej%otb%,Cot%3t=shtP,MicrosoftSystem64,.pcl-data,.pcl-stateMARKERSinscripts/check-malware-markers.mjs, asserted by themarker listtest group.git, dependencies, build output, and the scanner test fixtures from production matchesSKIP_DIRS+SKIP_PATHS, proven by tests and by the repository scanning cleanscripts/check-malware-markers.test.mjs(19 tests) +scripts/fixtures/malware-markers/path/to/file.ext:LINE: <marker name>on stdout, asserted by a testdocs/MALWARE_MARKERS.md→ Updating the marker list, plus a section indocs/CI.mdincludesonly; tests assert no evaluation and no dynamic-evaluation primitives in the sourceHow it works
scripts/check-malware-markers.mjswalks the working tree, reads each file asUTF-8, and does a fixed-string
includessearch per line against theMARKERSarray. It deliberately does not use regular expressions, so no untrusted
content is ever parsed as a pattern, and it never imports,
evals, or executesanything it reads. Scanning every file type (not an extension allowlist) means a
marker cannot hide in a file type the scanner has never heard of.
Report format — marker name, path, line number, and nothing else:
Matches go to stdout, the summary to the structured log on stderr. The matched
line is never returned by the API or printed, so a marker cannot be read back
out of a CI log.
Exclusions
.gitnode_modules,.pnpm-storedist,build,out,.next,.turbo,coverage,.nyc_output,target,artifacts,tmp-bindings,test_snapshotsscripts/check-malware-markers.mjs,scripts/check-malware-markers.test.mjs,scripts/fixtures/malware-markers/The marker strings are intentionally not repeated in
docs/CI.mdordocs/MALWARE_MARKERS.md, because those files are themselves scanned — the docsexplain where the list lives instead.
CI
.github/workflows/malware-markers.ymlruns on push tomainand on pullrequests:
node --test scripts/check-malware-markers.test.mjsthennode scripts/check-malware-markers.mjs. There is no install step — the scannerand the shared logger have no external dependencies — and
permissionsiscontents: read, matching the other read-only gates.The job is named
check, the same job name as the other lightweight gates(
Bindings check,Line lengths check), which places it inside the requiredstatus-check context the branch ruleset already enforces.
Supply-chain review
markers:checkandmarkers:test, which invokenodeon first-party scripts. No dependency was added or removed andpnpm-lock.yamlis untouched..vscode/, workflow, or other editor/config file changes. Changed: added.github/workflows/malware-markers.yml, a new read-only gate. No existing workflow,.vscode/or editor config was modified.preinstall/postinstall) was added.Testing
All run locally on this branch:
What the 19 tests prove:
.git,node_modules,dist,build,target,coverage,artifacts,.turboand the scanner's own files are not reported, while an unrelated file in the same directory still is;path:line: <marker>, and never prints the surrounding sentinel text;eval(,new Function(,vm.runIn,spawnSync/execSync, or dynamicimport(.Manual probe outside the test suite: a marker planted in
probe/hit.jsexited 1and printed
probe/hit.js:1: <marker>, while the same marker planted under.git,node_modules,dist,build,scripts/fixtures/malware-markers/andthe scanner source produced no match.
Docs
docs/MALWARE_MARKERS.md— guarantees, report format, exclusions, the step-by-step procedure for adding or removing a marker, test coverage, and the known limits (fixed-string only; split, encoded or compressed markers are out of scope).docs/CI.md— new Malware marker scan section linking to it.Closes #480