Rules

GiTRay runs 35 rules over every file of the repository. A rule adds its weight to the score once, using its strongest finding. The total is capped at 100: below 30 is clean, from 30 suspicious, from 70 dangerous. Some rules raise their weight for stronger evidence (for example an install script that also downloads something). Code rules weigh less inside documentation, where commands are usually examples, and inside search patterns and comments in source code, which never run: security tools describe attacks this way.

Malicious dependencies

GR-DEP-001+70

Depends on a known malicious package

The repository's own code can be clean while npm install or pip install pulls in a package that security researchers have confirmed as malware (OpenSSF malicious-packages data, served by OSV). Installing the dependencies runs it. This is how fake job-interview projects and typosquatted packages deliver stealers.

Runs automatically

GR-AUTO-001+10

package.json runs a script on install

npm runs lifecycle scripts (preinstall, postinstall, ...) automatically during "npm install", before you have used or reviewed anything. Malicious packages and repositories use them to run code on the developer's machine.

files: package.json

GR-AUTO-002+10

setup.py runs commands or uses the network

pip executes setup.py when the package is installed from source. Reading a compiler version is common, but downloading data, running download tools or evaluating decoded code there means a payload runs on install.

files: setup.py

GR-AUTO-003+35

VS Code task runs when the folder is opened

A task with "runOn": "folderOpen" starts automatically when the repository is opened in VS Code (once the workspace is trusted). Fake job-interview and "take-home test" repositories use this to run malware on developers' machines.

files: .vscode/tasks.json, *.code-workspace

GR-AUTO-004+10

Visual Studio project runs a command on build

Build events and Exec tasks run commands as soon as the project is built in Visual Studio. Campaigns targeting security researchers shipped project files whose build event launched PowerShell to install a backdoor.

files: *.csproj, *.vbproj, *.fsproj, *.vcxproj, *.vcproj, *.props, *.targets, *.proj

GR-AUTO-005+5

Rust build script runs commands or downloads

Cargo compiles and runs build.rs before building the crate, so it runs on "cargo build" and in IDEs that build on open. Calling git or pkg-config is normal; downloading or starting PowerShell is how malicious crates deliver payloads.

files: build.rs

GR-AUTO-006+10

Dev container runs a command on your computer

initializeCommand runs on your own machine, not inside the container, as soon as you choose "Reopen in Container" in VS Code or start the dev container with another tool. A command that downloads or decodes something there is a payload, not a setup step.

files: .devcontainer/devcontainer.json, .devcontainer.json, .devcontainer/*/devcontainer.json

GR-AUTO-007+30

Editor settings run a program from the repository

Workspace settings such as git.path, php.validate.executablePath or a terminal profile tell VS Code which program to start. When they point to a file inside the repository, VS Code runs the attacker's program as soon as the folder is opened and trusted.

files: .vscode/settings.json, *.code-workspace

GR-AUTO-008+15

AI coding assistant runs commands automatically

Claude Code, Cursor and Gemini CLI run hook commands from the project's settings on their own (for example when a session starts), and start the MCP servers a project declares. Opening a poisoned repository with an AI assistant then runs its commands.

files: .claude/settings.json, .claude/settings.local.json, .cursor/hooks.json, .gemini/settings.json, .mcp.json, .cursor/mcp.json, .vscode/mcp.json

GR-AUTO-009+35

npm configuration injects code into every script

A project .npmrc applies to every npm command run in the folder. node-options with --require or --import loads a file into every Node process npm starts, and script-shell replaces the shell that runs every script, so a single npm install or npm test runs it.

files: .npmrc

GR-AUTO-010+20

direnv file downloads code

direnv runs .envrc every time you enter the folder in a terminal, once you have allowed it with "direnv allow". Exporting variables is normal; downloading or fetching a remote script there runs code you have not seen on every cd.

files: .envrc

Malicious code patterns

GR-CODE-001+45+5 in docs, search patterns and comments

Decodes hidden code and executes it

Code is decoded (base64, hex, zlib, ...) and handed straight to an interpreter. Legitimate projects rarely hide what they run; malware does this to get past reviewers and scanners.

GR-CODE-002+35ignored in docs, search patterns and comments

Downloads a script and pipes it into a shell

A remote script is downloaded and executed immediately, without being saved or reviewed. Whoever controls that URL controls your machine.

GR-CODE-003+40+5 in docs, search patterns and comments

Reads browser password or cookie stores

References the files where browsers keep saved passwords, cookies and the keys that decrypt them. Info-stealer malware goes after exactly these files.

GR-CODE-004+25+3 in docs, search patterns and comments

Reads SSH private keys

References SSH private keys or authorized_keys. Stolen private keys give access to servers and GitHub; writing to authorized_keys plants a backdoor.

GR-CODE-005+35+5 in docs, search patterns and comments

Reads cryptocurrency wallet files

References wallet files, wallet application folders or wallet browser extensions. Crypto-stealing malware searches for exactly these.

GR-CODE-006+25+5 in docs, search patterns and comments

Sends data to a Discord webhook or Telegram bot

A hard-coded Discord webhook or Telegram bot token is the most common way stealer malware ships stolen passwords, cookies and files to the attacker: no server needed.

GR-CODE-007+35+5 in docs, search patterns and comments

Uses Windows tools to download, hide or persist

Built-in Windows programs (certutil, bitsadmin, mshta, rundll32, regsvr32) can download and run payloads, and Defender exclusions, hidden PowerShell windows and Run keys are how malware hides and survives a reboot. Normal projects almost never need these.

GR-CODE-008+10+3 in docs, search patterns and comments

Executes the contents of a file

Code reads another file and runs it. Reading a version file this way is an old Python habit, but running a Markdown, text or image file means the real payload is hidden somewhere reviewers and scanners treat as harmless data.

Hidden or obfuscated content

GR-OBF-001+15

Long random-looking string (possible hidden payload)

Long strings that look random are typical of encoded or encrypted payloads that are decoded at runtime. They can also be harmless data (keys, fonts, test vectors), so this is a weak signal on its own.

GR-OBF-002+15

Invisible bidirectional control characters in code

Unicode bidirectional overrides make code display in a different order than the compiler reads it ("Trojan Source", CVE-2021-42574): a reviewer sees a comment while the interpreter runs a command. Right-to-left text is fine in prose, never inside code.

GR-OBF-003+40

Code hidden far to the right of a line

Hundreds of spaces push code past the edge of the screen, so GitHub and editors show an innocent-looking line while the hidden part runs. Fake GitHub projects use this to smuggle loaders into otherwise working code.

GR-OBF-004+40

Invisible Unicode characters hiding data or code

Long runs of variation selectors, tag or zero-width characters render as nothing but can encode a whole program; recent supply-chain worms hid their loaders this way. Blank-looking Hangul fillers can also be used as invisible variable names.

Social engineering

GR-SOC-001+25

Asks you to disable your antivirus

Telling users to turn off Windows Defender, add an exclusion or ignore a "false positive" is the signature move of fake cheat, crack and tool repositories: the download would be blocked otherwise.

files: *.md, *.markdown, *.mdown, *.rst, *.adoc, *.asciidoc, *.txt, README*

Binary files

GR-BIN-001+20

Executable file committed to the repository

A ready-to-run program inside a source repository cannot be reviewed like code: what you see on GitHub is not what runs. Fake projects ship the payload this way, often next to source code that does nothing. Windows shortcut (.lnk) files are a common malware launcher.

GR-BIN-002+30

Password-protected archive in the repository

An encrypted archive cannot be inspected by GitHub, antivirus or this scanner. Legit projects have no reason to commit one; malware does it to slip past every scanner.

GR-BIN-003+70

Antivirus engines detect a file (VirusTotal)

VirusTotal runs files through about 70 antivirus engines. This exact file, matched by its SHA-256 fingerprint (nothing is downloaded or run), is detected by some of them. Five or more detections mean known malware. A few detections are common false positives on installers and small launchers, so they weigh little.

Repository signals

GR-REPO-001+10

Owner account is brand new

Fake repositories are usually pushed from accounts created days earlier and abandoned once they are reported. A new account is not a problem in itself, but it adds weight to other findings.

GR-REPO-002+5

Repository was created very recently

Malware campaigns create fresh repositories (often copies of popular projects) and promote them before anyone looks closely. A weak signal that only matters together with other findings.

GR-REPO-003+5

Files are left out of GitHub's download archive

A .gitattributes export-ignore rule keeps these files out of the archive GitHub serves, yet "git clone" still delivers them. Packages often use it to drop tests, but it is also a way to hide a payload from scanners that read the archive. GiTRay downloads these files separately and scans them like the rest.

CI workflows

GR-CI-001+5

CI workflow pipes a download into a shell

The CI configuration downloads a script and runs it on the build server (GitHub Actions, GitLab CI, Azure Pipelines, ...). That is not the machine of whoever clones the repository, so it weighs little; it still means whoever controls that URL controls the build.

files: .github/workflows/*.yml, .github/workflows/*.yaml, .gitlab-ci.yml, .gitlab/ci/*.yml, .travis.yml, .circleci/*.yml, appveyor.yml, .appveyor.yml, bitbucket-pipelines.yml, .drone.yml, .woodpecker.yml, .woodpecker/*.yml, .buildkite/*.yml, cloudbuild.yaml, cloudbuild.yml, codemagic.yaml, Jenkinsfile, azure-pipelines*.yml, azure-pipelines/*.yml, azure-pipelines/*/*.yml, azure-pipelines/*/*/*.yml, .azure-pipelines/*.yml, .pipelines/*.yml