git-tag-guardian 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.guardian.yml ADDED
@@ -0,0 +1,38 @@
1
+ # git-tag-guardian — конфигурация
2
+ # Положите этот файл в корень проекта
3
+
4
+ checks:
5
+ # Проверка: git-зависимости должны ссылаться на SHA, не на теги
6
+ shaPinning: true
7
+
8
+ # Проверка: обнаружение lifecycle-скриптов (postinstall и др.)
9
+ postinstallHooks: true
10
+
11
+ # Проверка: верификация SHA тегов через GitHub API
12
+ # Требует GITHUB_TOKEN
13
+ tagIntegrity: true
14
+
15
+ # Проверка: .tar.gz хеш должен совпадать с baseline
16
+ tarballIntegrity: true
17
+
18
+ # Проверка: GitHub Actions должны использовать SHA pinning
19
+ actionsPinning: true
20
+
21
+ # Пакеты, которым разрешены lifecycle-скрипты
22
+ # (не будут генерировать alert)
23
+ allowedLifecyclePackages: []
24
+ # - electron
25
+ # - sharp
26
+ # - better-sqlite3
27
+ # - @parcel/watcher
28
+
29
+ # Файл baseline (содержит проверенные SHA)
30
+ baselineFile: ".guardian-baseline.json"
31
+
32
+ # GitHub Actions: owner/action паттерны, которым доверяем
33
+ # (будут иметь severity: low вместо high)
34
+ trustedActions:
35
+ - "actions/*"
36
+
37
+ # Минимальный severity для CI fail
38
+ failOnSeverity: high
package/README.md ADDED
@@ -0,0 +1,280 @@
1
+ # git-tag-guardian
2
+
3
+ **Zero-dependency supply chain defense for Node.js and Bun projects.**
4
+
5
+ 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.
6
+
7
+ > Built by **CanisterWorm / TeamPCP** as a practical countermeasure to real-world tag rewrite exploitation techniques.
8
+
9
+ ---
10
+
11
+ ## The Problem
12
+
13
+ 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.
14
+
15
+ **Attack chain:**
16
+
17
+ ```
18
+ 1. Attacker forks your dependency
19
+ 2. Adds malicious code in the fork (postinstall exfiltration, modified source, etc.)
20
+ 3. Pushes to fork — commit lands in shared GitHub Object Store
21
+ 4. Rewrites the tag in upstream: PATCH /git/refs/tags/v1.0.0 { sha: "malicious", force: true }
22
+ 5. GitHub regenerates .tar.gz automatically
23
+ 6. Next `npm install` pulls compromised code
24
+ 7. postinstall runs silently — steals env vars, SSH keys, tokens
25
+ ```
26
+
27
+ This tool detects **every stage** of that chain.
28
+
29
+ ---
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ # As a dev dependency
35
+ npm install --save-dev git-tag-guardian
36
+
37
+ # Or run directly
38
+ npx git-tag-guardian audit
39
+ ```
40
+
41
+ No external dependencies. Works on Node.js >= 18 and Bun.
42
+
43
+ ---
44
+
45
+ ## Quick Start
46
+
47
+ ```bash
48
+ # 1. Full audit of current project
49
+ npx git-tag-guardian audit
50
+
51
+ # 2. Create a baseline (records current SHA hashes)
52
+ npx git-tag-guardian baseline
53
+
54
+ # 3. Install git hooks (pre-commit + post-merge)
55
+ npx git-tag-guardian hooks-install
56
+
57
+ # 4. Run in CI (exits 1 on critical/high findings)
58
+ npx git-tag-guardian audit --ci
59
+ ```
60
+
61
+ ---
62
+
63
+ ## 5 Security Checks
64
+
65
+ ### 1. SHA Pinning
66
+
67
+ 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.
68
+
69
+ ```
70
+ [HIGH] Dependency "logger" references tag "v1.0.0" instead of SHA
71
+ fix: Replace with full SHA commit hash
72
+ ```
73
+
74
+ ### 2. Postinstall Hook Detection
75
+
76
+ Scans every package in `node_modules/` for lifecycle scripts (`preinstall`, `install`, `postinstall`, `prepare`, etc.) and analyzes their content for 15+ suspicious patterns:
77
+
78
+ | Pattern | Risk |
79
+ |---------|------|
80
+ | `curl` / `wget` / `fetch()` to external URLs | Data exfiltration |
81
+ | `process.env` access | Credential theft |
82
+ | `.ssh/` access | SSH key theft |
83
+ | `.bashrc` / `.zshrc` modification | Persistent backdoor |
84
+ | `.npmrc` modification | Registry hijacking |
85
+ | `child_process` / `exec` / `eval` | Arbitrary code execution |
86
+ | `Buffer.from(..., 'base64')` | Obfuscation |
87
+ | `os.userInfo()` / `os.hostname()` | Reconnaissance |
88
+ | `dns.resolve` / `dns.lookup` | DNS exfiltration |
89
+
90
+ Packages with 3+ suspicious patterns are flagged as **CRITICAL**.
91
+
92
+ ### 3. Tag Integrity (GitHub API)
93
+
94
+ 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).
95
+
96
+ ```
97
+ [CRIT] TAG REWRITE DETECTED: owner/repo#v1.0.0 SHA changed!
98
+ baseline SHA: 1fadba8...
99
+ remote SHA: 16e4324... (from fork!)
100
+ ```
101
+
102
+ Requires `GITHUB_TOKEN` environment variable.
103
+
104
+ ### 4. Tarball Integrity
105
+
106
+ 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.
107
+
108
+ ```
109
+ [CRIT] TARBALL CHANGED: "logger" .tar.gz hash changed!
110
+ baseline: 475308ac...
111
+ current: 4204c3e4...
112
+ ```
113
+
114
+ ### 5. GitHub Actions Pinning
115
+
116
+ 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.
117
+
118
+ ```
119
+ [HIGH] Action "third-party/action@v2" uses tag instead of SHA!
120
+ fix: uses: third-party/action@<40-char-sha> # v2
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Baseline System
126
+
127
+ The baseline records known-good SHA hashes for dependencies, tags, and tarballs. Subsequent audits compare current state against the baseline to detect drift.
128
+
129
+ ```bash
130
+ # Create initial baseline
131
+ npx git-tag-guardian baseline
132
+
133
+ # Commit it
134
+ git add .guardian-baseline.json
135
+ git commit -m "Add supply chain baseline"
136
+ ```
137
+
138
+ The baseline file (`.guardian-baseline.json`) should be committed to your repository so every developer and CI runner uses the same reference.
139
+
140
+ ---
141
+
142
+ ## GitHub Actions Workflow
143
+
144
+ A ready-to-use CI workflow is included at `.github/workflows/supply-chain-guard.yml`:
145
+
146
+ - Runs on every PR that touches `package.json` / `package-lock.json`
147
+ - Runs on push to `main` / `master`
148
+ - Scheduled daily cron for tag rewrite detection between commits
149
+ - Posts findings as PR comments on failure
150
+ - All actions in the workflow itself are SHA-pinned
151
+
152
+ ```yaml
153
+ # Key: install with --ignore-scripts to prevent postinstall execution
154
+ - run: npm ci --ignore-scripts
155
+ - run: npx git-tag-guardian audit --ci
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Git Hooks
161
+
162
+ ```bash
163
+ npx git-tag-guardian hooks-install
164
+ ```
165
+
166
+ Installs two hooks:
167
+
168
+ - **pre-commit** — blocks commits that introduce SHA drift or new lifecycle hooks
169
+ - **post-merge** — automatically checks dependencies after `git pull`
170
+
171
+ ---
172
+
173
+ ## Configuration
174
+
175
+ Create `.guardian.yml` in your project root (optional — sensible defaults are used otherwise):
176
+
177
+ ```yaml
178
+ checks:
179
+ shaPinning: true
180
+ postinstallHooks: true
181
+ tagIntegrity: true # requires GITHUB_TOKEN
182
+ tarballIntegrity: true
183
+ actionsPinning: true
184
+
185
+ # Packages allowed to have lifecycle scripts
186
+ allowedLifecyclePackages:
187
+ - electron
188
+ - sharp
189
+ - better-sqlite3
190
+
191
+ # Actions owners trusted (severity: low instead of high)
192
+ trustedActions:
193
+ - actions/*
194
+
195
+ # Baseline file name
196
+ baselineFile: .guardian-baseline.json
197
+
198
+ # Minimum severity to fail CI
199
+ failOnSeverity: high
200
+ ```
201
+
202
+ ---
203
+
204
+ ## CLI Reference
205
+
206
+ ```
207
+ COMMANDS:
208
+ audit Full project audit (all 5 checks)
209
+ baseline Create/update SHA baseline
210
+ verify Quick check (SHA drift + postinstall only)
211
+ hooks-install Install git hooks (pre-commit, post-merge)
212
+ help Show help
213
+
214
+ FLAGS:
215
+ --ci CI mode (exit 1 on critical/high findings)
216
+ --cwd <path> Project root (default: cwd)
217
+ --token <tok> GitHub PAT for API checks (or GITHUB_TOKEN env)
218
+ --output <file> Save report as JSON
219
+ --no-color Disable colors
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Integration with AI Coding Agents
225
+
226
+ This project ships companion skills for Claude Code and OpenCode that automatically run supply chain checks when the agent installs npm packages:
227
+
228
+ - **[claude-supply-chain-skill](https://github.com/47-ron/claude-supply-chain-skill)** — Claude Code / Anthropic CLI skill
229
+ - **[opencode-supply-chain-skill](https://github.com/47-ron/opencode-supply-chain-skill)** — OpenCode agent skill
230
+
231
+ These skills hook into the agent's `npm install` / `bun install` workflow and block installation if critical findings are detected.
232
+
233
+ ---
234
+
235
+ ## How It Works (Technical)
236
+
237
+ ### Git Tag Rewrite Attack
238
+
239
+ ```
240
+ Upstream repo: owner/logger
241
+ refs/tags/v1.0.0 → commit abc123 (clean)
242
+
243
+ Attacker fork: attacker/logger
244
+ branch: malicious → commit xyz789 (backdoor)
245
+
246
+ API call (with push access):
247
+ PATCH /repos/owner/logger/git/refs/tags/v1.0.0
248
+ { "sha": "xyz789", "force": true }
249
+
250
+ Result:
251
+ refs/tags/v1.0.0 → commit xyz789 (backdoor!)
252
+ .tar.gz regenerated with malicious content
253
+ npm install pulls backdoor automatically
254
+ ```
255
+
256
+ ### Why SHA Pinning Stops It
257
+
258
+ 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.
259
+
260
+ ---
261
+
262
+ ## Severity Levels
263
+
264
+ | Severity | Meaning | CI Impact |
265
+ |----------|---------|-----------|
266
+ | `critical` | Active attack indicator (SHA drift, tag rewrite, dangerous hooks) | Fail |
267
+ | `high` | Missing protection (tag-based deps, unpinned actions) | Fail |
268
+ | `medium` | Informational risk (short SHA, missing baseline) | Pass |
269
+ | `low` | Best practice suggestion | Pass |
270
+ | `info` | Informational only | Pass |
271
+
272
+ ---
273
+
274
+ ## License
275
+
276
+ MIT
277
+
278
+ ---
279
+
280
+ *CanisterWorm / TeamPCP — Practical security tooling for the Node.js ecosystem.*