RepoGuard is a lightweight bash script designed to audit third-party repositories before you run npm install or npm start. Script created from "Real-world malware analysis" by Ryan Oberholzer / local copy of article. This tool helps detect backdoors, obfuscated code, and credential-stealing patterns common in "technical assessment" scams.
In modern supply-chain attacks, malware is often hidden in plain sight—stitched to the end of config files like tailwind.config.js or tucked into post-install scripts. This tool scans for:
- Exfiltration: Attempts to send data to unknown external URLs.
- Credential Theft: Accessing .ssh folders or process.env secrets.
- Obfuscation: Unusually long config files (100+ lines) containing hex/Base64 strings.
- Remote Execution: Use of eval(), exec(), or child_process.
- A Unix-based environment (Linux, macOS, WSL).
- grep and wc installed (standard on most systems).
⇡ Return to the Table of Contents
Clone this repository or download the check-repo.sh file and make the script executable:
git clone https://github.com/badj/repoguard.git
cd repoguard
chmod +x check-repo.sh⇡ Return to the Table of Contents
repoguard
├── .github/
│ └── workflows/
│ └── test.yml // GitHub Action/Workflow to run BATS-CORE tests on every commit and scheduled intervals
├── Article // local copy of article
│ └── Real-world-malware-analysis-by-Ryan-Oberholzer.pdf
├── LICENSE
├── README.md
├── test/
│ └── check-repo.bats // BATS-CORE test file
├── babel.config.js // Test Sample File
├── backend // Test Sample Folder
│ └── package.json // Test Sample File
├── check-repo.sh // RepoGuard Bash Script
├── decoder-catch.js // Test Sample File
├── package.json // Test Sample File
├── postcss.config.js // Test Sample File
├── tailwind.config.js // Test Sample File
├── vulnerable_test.ts // Test Sample File
└── webpack.config.js // Test Sample File
3 directories, 12 files
⇡ Return to the Table of Contents
Move the script - check-repo.sh into the root of the project you want to inspect and run:
./check-repo.sh⇡ Return to the Table of Contents
jjbadenhorst:repoguard (main) % chmod +x check-repo.sh
jjbadenhorst:repoguard (main) % ./check-repo.sh
--- 1. Dangerous patterns (eval, exec, private keys) ---
(none found)
--- 2. Base64 / encoded strings ---
(none found)
--- 3. Config file lengths (obfuscation = very long) ---
(none found)
--- 4. Post install / preinstall scripts ---
(none found)
--- 5. Suspicious dependencies (0.0.0, 0.0.1) ---
(none found)
=== DONE ===
Review the output above. If you see:
- Unknown external URLs (not Infura, Alchemy, your backend)
- process.env.Wallet* or process.env.*Private* sent anywhere
- Config files with 100+ lines (scroll to end and look for hex/obfuscation)
- post install scripts from unknown packages
-> DO NOT RUN npm install or npm start. Investigate further or run in Docker only!
Refer to Project Structure for the test files used to generate this output.
Run
check-repo.shin this project to demo DANGEROUS PATTERNS found.
jjbadenhorst:repoguard (main) % ./check-repo.sh
--- 1. Dangerous patterns (eval, exec, private keys) ---
./vulnerable_test.ts:8: eval(input); // Should be caught
./vulnerable_test.ts:13:child_process.exec(command); // Should be caught
./vulnerable_test.ts:16:const dynamicFunction = new Function('a', 'b', 'return a + b'); // Should be caught
./vulnerable_test.ts:20: apiKey: process.env.PrivateKey, // Should be caught
./vulnerable_test.ts:21: walletId: process.env.WalletAddress, // Should be caught
./vulnerable_test.ts:22: token: process.env.SecretToken, // Should be caught
./vulnerable_test.ts:23: encryption: process.env.EKEY_VALUE, // Should be caught
--- 2. Base64 / encoded strings ---
./decoder-catch.js:8: Buffer[at(0x66)](s1, r)[aw(0x68)+au(0x4c)](t) // Buffer.from(s1, 'base64').toString('utf8') // Should be caught
--- 3. Config file lengths (obfuscation = very long) ---
tailwind.config.js: 126 lines
^ WARNING: Config > 100 lines - scroll to end and check for obfuscated code
webpack.config.js: 126 lines
^ WARNING: Config > 100 lines - scroll to end and check for obfuscated code
babel.config.js: 126 lines
^ WARNING: Config > 100 lines - scroll to end and check for obfuscated code
postcss.config.js: 126 lines
^ WARNING: Config > 100 lines - scroll to end and check for obfuscated code
--- 4. Post install / preinstall scripts ---
package.json: "postinstall": "npx ShouldBeCaught test 1",
package.json: "preinstall": "npx ShouldBeCaught test 2",
package.json: "prepare": "npx ShouldBeCaught test 3"
backend/package.json: "postinstall": "npx ShouldBeCaught test 1",
backend/package.json: "preinstall": "npx ShouldBeCaught test 2",
backend/package.json: "prepare": "npx ShouldBeCaught test 3"
--- 5. Suspicious dependencies (0.0.0, 0.0.1) ---
package.json: "@catchMe/test4ShouldBeCaught": "0.0.0",
package.json: "@catchMe/test5ShouldBeCaught": "0.0.1",
backend/package.json: "@catchMe/test4ShouldBeCaught": "0.0.0",
backend/package.json: "@catchMe/test5ShouldBeCaught": "0.0.1",
=== DONE ===
Review the output above. If you see:
- Unknown external URLs (not Infura, Alchemy, your backend)
- process.env.Wallet* or process.env.*Private* sent anywhere
- Config files with 100+ lines (scroll to end and look for hex/obfuscation)
- post install scripts from unknown packages
-> DO NOT RUN npm install or npm start. Investigate further or run in Docker only!
⇡ Return to the Table of Contents
- Dangerous Code: Looks for eval, exec, and references to private keys.
- Encoding: Detects Base64 or Buffer from calls used to hide malicious payloads.
- Config Integrity: Flags configuration files (Tailwind, Webpack, etc.) that are suspiciously long.
- Lifecycle Hooks: Scans package.json for pre-install or post-install scripts that run code automatically.
- Suspicious Dependencies: Flags packages using placeholder versions like 0.0.0.
⇡ Return to the Table of Contents
- Never trust a "Technical Assessment" blindly. If a recruiter pressures you to run code immediately, be cautious.
- Use Docker. If you must run the code, run it in a container without mounting your home directory.
- Review the Output. This script is a helper, not a guarantee.
- If it flags a 500-line tailwind.config.js, open that file and scroll to the bottom!
⇡ Return to the Table of Contents
# Install BATS (once)
sudo apt-get install bats # or brew install bats-core on macOS
# Run tests
bats test/check-repo.bats
# OR Run tests with options for tracing and timings
bats --tap --trace --timing- Tests are also run automatically on push/PR via GitHub Actions:
- GitHub Action/Workflow implemented to run BATS-CORE tests on every commit and scheduled intervals.
Expected output for a successful / completed test suite local run with options
--trace --timingfor 9 tests passing
repoguard (main) % bats --tap --trace --timing check-repo.bats
1..9
ok 1 check-repo.sh exists and is executable in 18ms
ok 2 script runs without errors (exit status 0) in 75ms
ok 3 detects dangerous patterns (eval, exec, Function, suspicious env vars) in 65ms
ok 4 detects base64 / encoded string obfuscation in 63ms
ok 5 flags long config files as potential obfuscation in 65ms
ok 6 detects postinstall / preinstall / prepare scripts in 64ms
ok 7 detects suspicious dependencies (0.0.0 / 0.0.1) in 74ms
ok 8 script always ends with === DONE === in 62ms
ok 9 script includes safety review message in 62ms
⇡ Return to the Table of Contents
1.Create a RepoGuard package for npm, install and publish to the npm registry
⇡ Return to the Table of Contents
Found a new malware pattern? Please open an Issue or submit a Pull Request to update the grep patterns.
⇡ Return to the Table of Contents
Distributed under the MIT License. See LICENSE for more information. Disclaimer: This tool is for educational and auditing purposes. It cannot detect 100% of all threats. Always use your best judgment when running untrusted code.