Package Exports
- git-tag-guardian
- git-tag-guardian/src/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (git-tag-guardian) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
git-tag-guardian
Zero-dependency supply chain defense for Node.js and Bun projects.
Detects and blocks Git Tag Rewrite attacks, postinstall backdoors, SHA drift in lockfiles, tarball tampering, and unpinned GitHub Actions — before they compromise your CI/CD or production.
Built by CanisterWorm / TeamPCP as a practical countermeasure to real-world tag rewrite exploitation techniques.
The Problem
Git tags are mutable. Anyone with push access to a repository can silently repoint a tag to a completely different commit — including one from a fork that contains a backdoor. npm, GitHub Actions, and Dockerfiles that reference dependencies by tag will then pull the malicious code without any warning.
Attack chain:
1. Attacker forks your dependency
2. Adds malicious code in the fork (postinstall exfiltration, modified source, etc.)
3. Pushes to fork — commit lands in shared GitHub Object Store
4. Rewrites the tag in upstream: PATCH /git/refs/tags/v1.0.0 { sha: "malicious", force: true }
5. GitHub regenerates .tar.gz automatically
6. Next `npm install` pulls compromised code
7. postinstall runs silently — steals env vars, SSH keys, tokensThis tool detects every stage of that chain.
Install
# As a dev dependency
npm install --save-dev git-tag-guardian
# Or run directly
npx git-tag-guardian auditNo external dependencies. Works on Node.js >= 18 and Bun.
Quick Start
# 1. Full audit of current project
npx git-tag-guardian audit
# 2. Create a baseline (records current SHA hashes)
npx git-tag-guardian baseline
# 3. Install git hooks (pre-commit + post-merge)
npx git-tag-guardian hooks-install
# 4. Run in CI (exits 1 on critical/high findings)
npx git-tag-guardian audit --ci5 Security Checks
1. SHA Pinning
Detects git dependencies in package.json that reference tags or branches instead of full 40-character SHA hashes. Tags can be rewritten; SHA hashes cannot.
[HIGH] Dependency "logger" references tag "v1.0.0" instead of SHA
fix: Replace with full SHA commit hash2. Postinstall Hook Detection
Scans every package in node_modules/ for lifecycle scripts (preinstall, install, postinstall, prepare, etc.) and analyzes their content for 15+ suspicious patterns:
| Pattern | Risk |
|---|---|
curl / wget / fetch() to external URLs |
Data exfiltration |
process.env access |
Credential theft |
.ssh/ access |
SSH key theft |
.bashrc / .zshrc modification |
Persistent backdoor |
.npmrc modification |
Registry hijacking |
child_process / exec / eval |
Arbitrary code execution |
Buffer.from(..., 'base64') |
Obfuscation |
os.userInfo() / os.hostname() |
Reconnaissance |
dns.resolve / dns.lookup |
DNS exfiltration |
Packages with 3+ suspicious patterns are flagged as CRITICAL.
3. Tag Integrity (GitHub API)
Queries the GitHub API to verify that tag SHA matches the baseline. Detects tag rewrite attacks in real-time. Also checks whether the commit belongs to the default branch or is a fork commit (strong indicator of attack).
[CRIT] TAG REWRITE DETECTED: owner/repo#v1.0.0 SHA changed!
baseline SHA: 1fadba8...
remote SHA: 16e4324... (from fork!)Requires GITHUB_TOKEN environment variable.
4. Tarball Integrity
Downloads .tar.gz archives from GitHub for tag-based dependencies and compares SHA256 hashes against the baseline. GitHub regenerates tarballs dynamically after tag rewrite — same URL, different content.
[CRIT] TARBALL CHANGED: "logger" .tar.gz hash changed!
baseline: 475308ac...
current: 4204c3e4...5. GitHub Actions Pinning
Scans .github/workflows/*.yml for uses: directives that reference actions by tag instead of SHA. An action tag rewrite gives attackers access to GITHUB_TOKEN, all secrets, and build artifacts.
[HIGH] Action "third-party/action@v2" uses tag instead of SHA!
fix: uses: third-party/action@<40-char-sha> # v2Baseline System
The baseline records known-good SHA hashes for dependencies, tags, and tarballs. Subsequent audits compare current state against the baseline to detect drift.
# Create initial baseline
npx git-tag-guardian baseline
# Commit it
git add .guardian-baseline.json
git commit -m "Add supply chain baseline"The baseline file (.guardian-baseline.json) should be committed to your repository so every developer and CI runner uses the same reference.
GitHub Actions Workflow
A ready-to-use CI workflow is included at .github/workflows/supply-chain-guard.yml:
- Runs on every PR that touches
package.json/package-lock.json - Runs on push to
main/master - Scheduled daily cron for tag rewrite detection between commits
- Posts findings as PR comments on failure
- All actions in the workflow itself are SHA-pinned
# Key: install with --ignore-scripts to prevent postinstall execution
- run: npm ci --ignore-scripts
- run: npx git-tag-guardian audit --ciGit Hooks
npx git-tag-guardian hooks-installInstalls two hooks:
- pre-commit — blocks commits that introduce SHA drift or new lifecycle hooks
- post-merge — automatically checks dependencies after
git pull
Configuration
Create .guardian.yml in your project root (optional — sensible defaults are used otherwise):
checks:
shaPinning: true
postinstallHooks: true
tagIntegrity: true # requires GITHUB_TOKEN
tarballIntegrity: true
actionsPinning: true
# Packages allowed to have lifecycle scripts
allowedLifecyclePackages:
- electron
- sharp
- better-sqlite3
# Actions owners trusted (severity: low instead of high)
trustedActions:
- actions/*
# Baseline file name
baselineFile: .guardian-baseline.json
# Minimum severity to fail CI
failOnSeverity: highCLI Reference
COMMANDS:
audit Full project audit (all 5 checks)
baseline Create/update SHA baseline
verify Quick check (SHA drift + postinstall only)
hooks-install Install git hooks (pre-commit, post-merge)
help Show help
FLAGS:
--ci CI mode (exit 1 on critical/high findings)
--cwd <path> Project root (default: cwd)
--token <tok> GitHub PAT for API checks (or GITHUB_TOKEN env)
--output <file> Save report as JSON
--no-color Disable colorsIntegration with AI Coding Agents
This project ships companion skills for Claude Code and OpenCode that automatically run supply chain checks when the agent installs npm packages:
- claude-supply-chain-skill — Claude Code / Anthropic CLI skill
- opencode-supply-chain-skill — OpenCode agent skill
These skills hook into the agent's npm install / bun install workflow and block installation if critical findings are detected.
How It Works (Technical)
Git Tag Rewrite Attack
Upstream repo: owner/logger
refs/tags/v1.0.0 → commit abc123 (clean)
Attacker fork: attacker/logger
branch: malicious → commit xyz789 (backdoor)
API call (with push access):
PATCH /repos/owner/logger/git/refs/tags/v1.0.0
{ "sha": "xyz789", "force": true }
Result:
refs/tags/v1.0.0 → commit xyz789 (backdoor!)
.tar.gz regenerated with malicious content
npm install pulls backdoor automaticallyWhy SHA Pinning Stops It
SHA-256 commit hashes are cryptographically unique. A rewritten tag points to a different SHA — but if your package-lock.json or baseline records the original SHA, the drift is immediately detectable.
Severity Levels
| Severity | Meaning | CI Impact |
|---|---|---|
critical |
Active attack indicator (SHA drift, tag rewrite, dangerous hooks) | Fail |
high |
Missing protection (tag-based deps, unpinned actions) | Fail |
medium |
Informational risk (short SHA, missing baseline) | Pass |
low |
Best practice suggestion | Pass |
info |
Informational only | Pass |
License
MIT
CanisterWorm / TeamPCP — Practical security tooling for the Node.js ecosystem.