@mr-aftab-ahmad-khan/depguard-cli 0.1.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/CHANGELOG.md +10 -0
- package/LICENSE +15 -0
- package/README.md +337 -0
- package/dist/chunk-BH7GFJ3G.js +592 -0
- package/dist/chunk-BH7GFJ3G.js.map +1 -0
- package/dist/cli.cjs +679 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +88 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +639 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +63 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] โ 2026-05-15
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `scan`, `audit`, and `baseline` commands for npm supply-chain auditing.
|
|
8
|
+
- Detects curl-pipe-shell install scripts, base64+eval, network calls to untrusted domains, and obfuscated one-liners.
|
|
9
|
+
- Typosquat detection via Levenshtein distance to the top-1000 packages.
|
|
10
|
+
- Configurable risk levels in `.depguardrc.json` plus `.driftignore` support.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 depguard-cli contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
package/README.md
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
# depguard-cli
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@mr-aftab-ahmad-khan/depguard-cli)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
|
|
7
|
+
**A free, fast, open-source supply-chain security scanner for npm.** `depguard-cli` audits your installed `node_modules` for the four attack vectors that cause real-world npm incidents:
|
|
8
|
+
|
|
9
|
+
- ๐ชช **Maintainer changes** โ new maintainers added since your trusted baseline
|
|
10
|
+
- ๐งจ **Suspicious install scripts** โ `preinstall`/`postinstall` lines that curl-pipe-shell, base64+eval, exfiltrate env vars, or hide behind obfuscation
|
|
11
|
+
- ๐ **Version anomalies** โ packages that bumped a major version in under 7 days, brand-new packages claiming to be popular
|
|
12
|
+
- โ๏ธ **Typosquats** โ installed names that are within Levenshtein 2 of a top-200 popular package
|
|
13
|
+
|
|
14
|
+
Socket.dev costs $19/month per developer. `depguard-cli` is free and fast enough to run in your `postinstall` hook or block PRs in CI.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g depguard-cli
|
|
22
|
+
pnpm add -g depguard-cli
|
|
23
|
+
yarn global add depguard-cli
|
|
24
|
+
|
|
25
|
+
# Or one-off:
|
|
26
|
+
npx depguard-cli scan
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
$ depguard scan
|
|
35
|
+
depguard report โ 2 package(s) with findings (of 412 scanned)
|
|
36
|
+
|
|
37
|
+
HIGH react@18.2.0 score=6
|
|
38
|
+
- high install-script:postinstall: postinstall script is suspicious (curl/wget piped to a shell or node)
|
|
39
|
+
|
|
40
|
+
CRITICAL reactt@0.0.1 score=10
|
|
41
|
+
- critical typosquat: Name closely resembles "react" โ likely typosquat
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Core Usage Examples
|
|
47
|
+
|
|
48
|
+
### 1. Scan and read the report
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
depguard scan
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Save a trusted baseline
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
depguard baseline
|
|
58
|
+
# depguard: baseline saved (412 packages)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3. Audit a single suspicious package
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
depguard audit reactt
|
|
65
|
+
# CRITICAL reactt@0.0.1 score=10
|
|
66
|
+
# - critical typosquat: Name closely resembles "react" โ likely typosquat
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 4. Fail PRs in CI
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
depguard scan --fail-on high
|
|
73
|
+
echo $? # 1 when any package is high+ severity
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 5. JSON output for `jq`
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
depguard scan --format json | jq '.packages[] | select(.worstSeverity == "critical")'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 6. Run on every install
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"scripts": {
|
|
87
|
+
"postinstall": "depguard scan --fail-on critical"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## CI/CD Integration Examples
|
|
95
|
+
|
|
96
|
+
### GitHub Actions
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
name: security
|
|
100
|
+
on: [pull_request]
|
|
101
|
+
jobs:
|
|
102
|
+
depguard:
|
|
103
|
+
runs-on: ubuntu-latest
|
|
104
|
+
steps:
|
|
105
|
+
- uses: actions/checkout@v4
|
|
106
|
+
- uses: actions/setup-node@v4
|
|
107
|
+
with: { node-version: 20 }
|
|
108
|
+
- run: npm ci
|
|
109
|
+
- run: npx depguard-cli scan --fail-on high
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### GitLab CI
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
depguard:
|
|
116
|
+
stage: test
|
|
117
|
+
image: node:20
|
|
118
|
+
script:
|
|
119
|
+
- npm ci
|
|
120
|
+
- npx depguard-cli scan --fail-on high
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Pre-commit hook with husky
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# .husky/pre-push
|
|
127
|
+
#!/bin/sh
|
|
128
|
+
npx depguard-cli scan --fail-on critical
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### postinstall
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"scripts": {
|
|
136
|
+
"postinstall": "depguard scan --fail-on critical --no-network"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Configuration Reference
|
|
144
|
+
|
|
145
|
+
`.depguardrc.json`:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"failOn": "high",
|
|
150
|
+
"ignore": ["some-known-noisy-pkg"],
|
|
151
|
+
"cacheTTL": 3600000,
|
|
152
|
+
"scanDepth": "all"
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
| Option | Type | Default | Description |
|
|
157
|
+
| -------------- | ----------- | ------------ | ---------------------------------------------------------- |
|
|
158
|
+
| `failOn` | `RiskLevel` | `undefined` | Exit code 1 when any package's worst severity โฅ this level |
|
|
159
|
+
| `ignore` | `string[]` | `[]` | Package names to skip |
|
|
160
|
+
| `baselinePath` | `string` | `~/.depguard/baseline.json` | Custom baseline location |
|
|
161
|
+
| `cacheTTL` | `number` | `3600000` | Registry cache TTL in ms |
|
|
162
|
+
| `scanDepth` | `"direct" \| "all"` | `"all"` | Direct dependencies only vs full tree |
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Risk Scoring Explained
|
|
167
|
+
|
|
168
|
+
### Maintainer changes
|
|
169
|
+
|
|
170
|
+
| Condition | Severity | Score |
|
|
171
|
+
| ---------------------------------------- | -------- | ----- |
|
|
172
|
+
| New maintainer added since baseline | high | 6 |
|
|
173
|
+
|
|
174
|
+
### Suspicious install scripts
|
|
175
|
+
|
|
176
|
+
| Pattern | Points |
|
|
177
|
+
| ---------------------------------------- | ------ |
|
|
178
|
+
| `curl`/`wget` piped to a shell or node | 5 |
|
|
179
|
+
| `base64` combined with `eval`/`exec` | 5 |
|
|
180
|
+
| Dynamic `new Function(...)` call | 3 |
|
|
181
|
+
| Reads `process.env.*` | 2 |
|
|
182
|
+
| Network call to a non-trusted domain | 3 |
|
|
183
|
+
| Long opaque token (>= 200 base64 chars) | 3 |
|
|
184
|
+
| One-liner > 300 chars without newlines | 2 |
|
|
185
|
+
|
|
186
|
+
Total is capped at 10. Severity mapping: 8-10 = critical, 5-7 = high, 3-4 = medium, 1-2 = low.
|
|
187
|
+
|
|
188
|
+
### Version anomaly
|
|
189
|
+
|
|
190
|
+
| Condition | Severity | Score |
|
|
191
|
+
| -------------------------------------------------- | -------- | ----- |
|
|
192
|
+
| Major version bump within 7 days of previous major | medium | 4 |
|
|
193
|
+
| Package first published < 30 days ago | low | 2 |
|
|
194
|
+
|
|
195
|
+
### Typosquat
|
|
196
|
+
|
|
197
|
+
| Levenshtein distance to a top-200 pkg | Severity | Score |
|
|
198
|
+
| ------------------------------------- | -------- | ----- |
|
|
199
|
+
| 1โ2 | critical | 10 |
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## TypeScript Types
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
import { scan, audit, type ScanResult, type PackageRisk, type RiskLevel } from "@mr-aftab-ahmad-khan/depguard-cli";
|
|
207
|
+
|
|
208
|
+
const result: ScanResult = await scan({ failOn: "high" });
|
|
209
|
+
for (const p of result.packages) {
|
|
210
|
+
console.log(p.name, p.worstSeverity, p.totalScore);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const single: PackageRisk | undefined = await audit("react");
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## CLI Reference
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
depguard scan [options]
|
|
222
|
+
--fail-on <severity> Exit 1 when worst severity โฅ this level (info|low|medium|high|critical)
|
|
223
|
+
--format <fmt> pretty | json (default pretty)
|
|
224
|
+
--no-network Skip registry lookups (uses cache only)
|
|
225
|
+
--depth <depth> direct | all (default all)
|
|
226
|
+
|
|
227
|
+
depguard baseline
|
|
228
|
+
Save the current node_modules maintainer list as the trusted baseline.
|
|
229
|
+
|
|
230
|
+
depguard audit <package>
|
|
231
|
+
Audit a single named package by fetching its registry metadata.
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Sample JSON output:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"packages": [
|
|
239
|
+
{
|
|
240
|
+
"name": "reactt",
|
|
241
|
+
"version": "0.0.1",
|
|
242
|
+
"worstSeverity": "critical",
|
|
243
|
+
"totalScore": 10,
|
|
244
|
+
"findings": [
|
|
245
|
+
{ "rule": "typosquat", "severity": "critical", "message": "Name closely resembles \"react\" โ likely typosquat", "score": 10 }
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
],
|
|
249
|
+
"scannedAt": "2026-01-12T10:01:22.000Z",
|
|
250
|
+
"generatedAt": "2026-01-12T10:01:23.130Z",
|
|
251
|
+
"totalPackages": 412
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Real-World Recipe โ Full CI Security Gate
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# 1. After a clean install, set the trusted baseline
|
|
261
|
+
npm ci
|
|
262
|
+
npx depguard-cli baseline
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
# 2. .github/workflows/security.yml โ blocks PRs with new high-risk dependencies
|
|
267
|
+
name: security
|
|
268
|
+
on: [pull_request, schedule]
|
|
269
|
+
on:
|
|
270
|
+
pull_request:
|
|
271
|
+
schedule:
|
|
272
|
+
- cron: "0 6 * * 1" # Mondays 06:00 UTC
|
|
273
|
+
|
|
274
|
+
jobs:
|
|
275
|
+
depguard:
|
|
276
|
+
runs-on: ubuntu-latest
|
|
277
|
+
steps:
|
|
278
|
+
- uses: actions/checkout@v4
|
|
279
|
+
- uses: actions/setup-node@v4
|
|
280
|
+
with: { node-version: 20 }
|
|
281
|
+
- run: npm ci
|
|
282
|
+
- id: scan
|
|
283
|
+
run: npx depguard-cli scan --fail-on high --format json > report.json || echo "had_findings=true" >> $GITHUB_OUTPUT
|
|
284
|
+
- if: ${{ steps.scan.outputs.had_findings == 'true' }}
|
|
285
|
+
run: |
|
|
286
|
+
curl -X POST -H 'Content-type: application/json' \
|
|
287
|
+
--data "$(jq -c '{text: "depguard found high-risk packages: " + (.packages | map(.name) | join(", "))}' report.json)" \
|
|
288
|
+
"${{ secrets.SLACK_WEBHOOK_URL }}"
|
|
289
|
+
- if: ${{ steps.scan.outputs.had_findings == 'true' }}
|
|
290
|
+
run: exit 1
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
```json
|
|
294
|
+
// 3. .depguardrc.json โ monorepo with a known noisy package
|
|
295
|
+
{
|
|
296
|
+
"failOn": "high",
|
|
297
|
+
"ignore": ["legacy-internal-tool"],
|
|
298
|
+
"scanDepth": "all"
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## False Positive Guide
|
|
305
|
+
|
|
306
|
+
The two most common false positives:
|
|
307
|
+
|
|
308
|
+
1. **`postinstall` runs `node-gyp` for native builds.** Already filtered; if you see it surface anyway, add the package to `ignore`.
|
|
309
|
+
2. **Major bump within 7 days.** Usually a frontend framework correcting a release. Add the specific package to `.depguardrc.json#ignore` once you've verified.
|
|
310
|
+
|
|
311
|
+
Workflow:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
depguard audit suspicious-pkg # confirm whether it's truly safe
|
|
315
|
+
# safe? add to ignore:
|
|
316
|
+
echo '{"ignore":["suspicious-pkg"]}' > .depguardrc.json
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Comparison Table
|
|
322
|
+
|
|
323
|
+
| Feature | npm audit | Socket.dev | **depguard-cli** |
|
|
324
|
+
| ----------------------------- | :-------: | :--------: | :--------------: |
|
|
325
|
+
| Maintainer-change detection | โ | โ
| โ
|
|
|
326
|
+
| Install-script analysis | โ | โ
| โ
|
|
|
327
|
+
| Typosquat detection | โ | โ
| โ
|
|
|
328
|
+
| Free tier | โ
| limited | โ
|
|
|
329
|
+
| CI integration | โ
| โ
| โ
|
|
|
330
|
+
| Offline mode | โ | โ | โ
|
|
|
331
|
+
| Self-hosted | n/a | โ | โ
|
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## License
|
|
336
|
+
|
|
337
|
+
MIT
|