npm-scan-plus 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/.eslintrc.json +32 -0
- package/.github/CODEOWNERS +3 -0
- package/.github/workflows/ci.yml +105 -0
- package/.prettierrc +10 -0
- package/FUNDING.yml +1 -0
- package/PLAN.md +151 -0
- package/README.md +150 -0
- package/bin/npm-scan +13 -0
- package/bin/npm-scan-wrap +100 -0
- package/dist/cli/index.d.ts +18 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +299 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/lib/blocklist.d.ts +45 -0
- package/dist/lib/blocklist.d.ts.map +1 -0
- package/dist/lib/blocklist.js +256 -0
- package/dist/lib/blocklist.js.map +1 -0
- package/dist/lib/extended.js +314 -0
- package/dist/lib/extended.js.map +1 -0
- package/dist/lib/integrity.js +247 -0
- package/dist/lib/integrity.js.map +1 -0
- package/dist/lib/patterns.d.ts +76 -0
- package/dist/lib/patterns.d.ts.map +1 -0
- package/dist/lib/patterns.js +414 -0
- package/dist/lib/patterns.js.map +1 -0
- package/dist/lib/registry.d.ts +42 -0
- package/dist/lib/registry.d.ts.map +1 -0
- package/dist/lib/registry.js +157 -0
- package/dist/lib/registry.js.map +1 -0
- package/dist/lib/scanner.d.ts +43 -0
- package/dist/lib/scanner.d.ts.map +1 -0
- package/dist/lib/scanner.js +432 -0
- package/dist/lib/scanner.js.map +1 -0
- package/dist/lib/vuln.js +284 -0
- package/dist/lib/vuln.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/jest.config.js +18 -0
- package/package.json +56 -0
- package/src/cli/index.ts +336 -0
- package/src/lib/blocklist.ts +239 -0
- package/src/lib/extended.ts +384 -0
- package/src/lib/integrity.ts +253 -0
- package/src/lib/patterns.ts +404 -0
- package/src/lib/registry.ts +146 -0
- package/src/lib/scanner.ts +447 -0
- package/src/lib/vuln.ts +321 -0
- package/src/types.ts +102 -0
- package/tests/blocklist.test.ts +89 -0
- package/tests/extended.test.ts +204 -0
- package/tests/patterns.test.ts +147 -0
- package/tests/scanner.test.ts +116 -0
- package/tests/vuln.test.ts +66 -0
- package/tsconfig.json +20 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"node": true,
|
|
4
|
+
"es2022": true,
|
|
5
|
+
"jest": true
|
|
6
|
+
},
|
|
7
|
+
"extends": [
|
|
8
|
+
"eslint:recommended",
|
|
9
|
+
"plugin:@typescript-eslint/recommended"
|
|
10
|
+
],
|
|
11
|
+
"parser": "@typescript-eslint/parser",
|
|
12
|
+
"parserOptions": {
|
|
13
|
+
"ecmaVersion": "latest",
|
|
14
|
+
"sourceType": "module",
|
|
15
|
+
"project": "./tsconfig.json"
|
|
16
|
+
},
|
|
17
|
+
"plugins": [
|
|
18
|
+
"@typescript-eslint"
|
|
19
|
+
],
|
|
20
|
+
"rules": {
|
|
21
|
+
"no-console": "off",
|
|
22
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
23
|
+
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
24
|
+
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
|
25
|
+
"no-case-declarations": "off"
|
|
26
|
+
},
|
|
27
|
+
"ignorePatterns": [
|
|
28
|
+
"dist/",
|
|
29
|
+
"node_modules/",
|
|
30
|
+
"coverage/"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main, develop]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, develop]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
node-version: [18.x, 20.x, 22.x]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout code
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Setup Node.js ${{ matrix.node-version }}
|
|
22
|
+
uses: actions/setup-node@v4
|
|
23
|
+
with:
|
|
24
|
+
node-version: ${{ matrix.node-version }}
|
|
25
|
+
cache: 'npm'
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: npm ci
|
|
29
|
+
|
|
30
|
+
- name: Build
|
|
31
|
+
run: npm run build
|
|
32
|
+
|
|
33
|
+
test:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
|
|
36
|
+
strategy:
|
|
37
|
+
matrix:
|
|
38
|
+
node-version: [18.x, 20.x, 22.x]
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- name: Checkout code
|
|
42
|
+
uses: actions/checkout@v4
|
|
43
|
+
|
|
44
|
+
- name: Setup Node.js ${{ matrix.node-version }}
|
|
45
|
+
uses: actions/setup-node@v4
|
|
46
|
+
with:
|
|
47
|
+
node-version: ${{ matrix.node-version }}
|
|
48
|
+
cache: 'npm'
|
|
49
|
+
|
|
50
|
+
- name: Install dependencies
|
|
51
|
+
run: npm ci
|
|
52
|
+
|
|
53
|
+
- name: Build
|
|
54
|
+
run: npm run build
|
|
55
|
+
|
|
56
|
+
- name: Run tests
|
|
57
|
+
run: npm test
|
|
58
|
+
|
|
59
|
+
- name: Upload coverage
|
|
60
|
+
uses: actions/upload-artifact@v4
|
|
61
|
+
if: matrix.node-version == '20.x'
|
|
62
|
+
with:
|
|
63
|
+
name: coverage
|
|
64
|
+
path: coverage/
|
|
65
|
+
|
|
66
|
+
lint:
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
|
|
69
|
+
steps:
|
|
70
|
+
- name: Checkout code
|
|
71
|
+
uses: actions/checkout@v4
|
|
72
|
+
|
|
73
|
+
- name: Setup Node.js
|
|
74
|
+
uses: actions/setup-node@v4
|
|
75
|
+
with:
|
|
76
|
+
node-version: 20
|
|
77
|
+
cache: 'npm'
|
|
78
|
+
|
|
79
|
+
- name: Install dependencies
|
|
80
|
+
run: npm ci
|
|
81
|
+
|
|
82
|
+
- name: Run ESLint
|
|
83
|
+
run: npm run lint
|
|
84
|
+
|
|
85
|
+
- name: Check formatting
|
|
86
|
+
run: npm run format -- --check
|
|
87
|
+
|
|
88
|
+
security:
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
|
|
91
|
+
steps:
|
|
92
|
+
- name: Checkout code
|
|
93
|
+
uses: actions/checkout@v4
|
|
94
|
+
|
|
95
|
+
- name: Setup Node.js
|
|
96
|
+
uses: actions/setup-node@v4
|
|
97
|
+
with:
|
|
98
|
+
node-version: 20
|
|
99
|
+
cache: 'npm'
|
|
100
|
+
|
|
101
|
+
- name: Install dependencies
|
|
102
|
+
run: npm ci
|
|
103
|
+
|
|
104
|
+
- name: Check for known vulnerabilities
|
|
105
|
+
run: npm audit --audit-level=moderate
|
package/.prettierrc
ADDED
package/FUNDING.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
github: cbuntingde
|
package/PLAN.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# npm Security Scanner - Implementation Plan
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
**Project name:** npm-scan
|
|
6
|
+
**Type:** Node.js CLI tool with library
|
|
7
|
+
**Core functionality:** Security scanner that detects malicious npm packages, supply chain attacks, and obfuscated code BEFORE installation, plus post-install forensics
|
|
8
|
+
|
|
9
|
+
## Architecture
|
|
10
|
+
|
|
11
|
+
### 1. Pre-Install Scanner (npm-scan pre)
|
|
12
|
+
|
|
13
|
+
Runs BEFORE npm install, intercepts package requests:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
User runs: npx npm-scan pre install lodash
|
|
17
|
+
ā
|
|
18
|
+
Scanner fetches lodash metadata from npm registry
|
|
19
|
+
ā
|
|
20
|
+
Checks against blocklists (known malicious packages)
|
|
21
|
+
ā
|
|
22
|
+
Analyzes package publisher reputation
|
|
23
|
+
ā
|
|
24
|
+
Checks for reported vulnerabilities
|
|
25
|
+
ā
|
|
26
|
+
Reports threat assessment
|
|
27
|
+
ā
|
|
28
|
+
Only then runs npm install (if approved)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. Post-Install Scanner (npm-scan post)
|
|
32
|
+
|
|
33
|
+
Runs AFTER npm install, scans downloaded packages:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
User runs: npx npm-scan post
|
|
37
|
+
ā
|
|
38
|
+
Scanner walks node_modules/
|
|
39
|
+
ā
|
|
40
|
+
For each package:
|
|
41
|
+
- Detects obfuscated code (base64, hex, eval wrappers)
|
|
42
|
+
- Checks for suspicious patterns (env exfil, crypto mining)
|
|
43
|
+
- Analyzes dependency chain for typosquatting
|
|
44
|
+
- Validates package integrity (hash verification)
|
|
45
|
+
ā
|
|
46
|
+
Reports findings
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Technical Implementation
|
|
50
|
+
|
|
51
|
+
### Core Library Functions
|
|
52
|
+
|
|
53
|
+
1. **`fetchPackageMetadata(name, registry)`** - Get package info from npm registry
|
|
54
|
+
2. **`checkBlocklist(package)`** - Verify against known malicious blocklists
|
|
55
|
+
3. **`analyzePublisher(publisher)`** - Check publisher reputation
|
|
56
|
+
4. **`detectVulnerabilities(version)`** - Check for known CVEs
|
|
57
|
+
5. **`scanPackageFiles(tarballPath)`** - Extract and analyze package contents
|
|
58
|
+
6. **`detectObfuscation(files)`** - Identify obfuscated code patterns
|
|
59
|
+
7. **`detectSuspiciousPatterns(files)`** - Check for malicious patterns
|
|
60
|
+
8. **`checkTyposquatting(name, deps)`** - Detect typosquatting in dependency tree
|
|
61
|
+
9. **`validateIntegrity(package, tarball)`** - Verify checksums
|
|
62
|
+
|
|
63
|
+
### CLI Commands
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Pre-install scan
|
|
67
|
+
npx npm-scan pre install <package> [--version <version>]
|
|
68
|
+
|
|
69
|
+
# Post-install scan
|
|
70
|
+
npx npm-scan post [--folder <path>]
|
|
71
|
+
|
|
72
|
+
# Full scan (both)
|
|
73
|
+
npx npm-scan scan <package> [--full]
|
|
74
|
+
|
|
75
|
+
# Blocklist management
|
|
76
|
+
npx npm-scan blocklist add <package>
|
|
77
|
+
npx npm-scan blocklist remove <package>
|
|
78
|
+
npx npm-scan blocklist list
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Patterns to Detect
|
|
82
|
+
|
|
83
|
+
**Obfuscation:**
|
|
84
|
+
- Base64 encoded strings in eval()
|
|
85
|
+
- Hex-encoded code
|
|
86
|
+
- String.fromCharCode() usage with eval
|
|
87
|
+
- Packed/minified with suspicious wrappers
|
|
88
|
+
|
|
89
|
+
**Malicious behavior:**
|
|
90
|
+
- Network requests to suspicious IPs/domains
|
|
91
|
+
- Environment variable exfiltration
|
|
92
|
+
- File system access beyond package scope
|
|
93
|
+
- Child process spawning
|
|
94
|
+
- Crypto mining detection
|
|
95
|
+
- Credential theft patterns
|
|
96
|
+
- .bash_history, .gitconfig access
|
|
97
|
+
|
|
98
|
+
**Supply chain attacks:**
|
|
99
|
+
- Typosquatting (lodash vs lodsh)
|
|
100
|
+
- Dependency confusion
|
|
101
|
+
- Unexpected peer dependencies
|
|
102
|
+
- Suspicious postinstall scripts
|
|
103
|
+
|
|
104
|
+
## File Structure
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
npm-scan/
|
|
108
|
+
āāā src/
|
|
109
|
+
ā āāā lib/
|
|
110
|
+
ā ā āāā registry.ts # npm registry API client
|
|
111
|
+
ā ā āāā blocklist.ts # Blocklist management
|
|
112
|
+
ā ā āāā scanner.ts # Core scanning logic
|
|
113
|
+
ā ā āāā patterns.ts # Detection patterns
|
|
114
|
+
ā ā āāā integrity.ts # Hash verification
|
|
115
|
+
ā āāā cli/
|
|
116
|
+
ā ā āāā pre.ts # Pre-install command
|
|
117
|
+
ā ā āāā post.ts # Post-install command
|
|
118
|
+
ā ā āāā index.ts # CLI entry
|
|
119
|
+
ā āāā types.ts
|
|
120
|
+
āāā bin/
|
|
121
|
+
ā āāā npm-scan
|
|
122
|
+
āāā tests/
|
|
123
|
+
ā āāā ...
|
|
124
|
+
āāā package.json
|
|
125
|
+
āāā tsconfig.json
|
|
126
|
+
āāā README.md
|
|
127
|
+
āāā .npmignore
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Blocklist Sources (MVP)
|
|
131
|
+
|
|
132
|
+
- npm Advisory DB (via npm audit API)
|
|
133
|
+
- GitHub Advisory Database
|
|
134
|
+
- Known malicious packages (maintained locally)
|
|
135
|
+
- User-defined blocklist
|
|
136
|
+
|
|
137
|
+
## Integration Options
|
|
138
|
+
|
|
139
|
+
1. **Standalone CLI:**
|
|
140
|
+
```bash
|
|
141
|
+
npx npm-scan pre install <package>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
2. **npm hook wrapper:**
|
|
145
|
+
Place script in PATH before npm to intercept
|
|
146
|
+
|
|
147
|
+
3. **Git hook integration:**
|
|
148
|
+
Run in pre-commit hook
|
|
149
|
+
|
|
150
|
+
4. **CI/CD integration:**
|
|
151
|
+
Use in pipeline before deployment
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# npm-scan š
|
|
2
|
+
|
|
3
|
+
**Security scanner for npm packages** - Pre and post-install scanning for malicious code, supply chain attacks, and obfuscated code.
|
|
4
|
+
|
|
5
|
+
## Why We Built This
|
|
6
|
+
|
|
7
|
+
npm package supply chain attacks are increasing at an alarming rate. Recent examples include:
|
|
8
|
+
|
|
9
|
+
- **TanStack (May 2026)**: Malicious package published to npm registry containing cryptocurrency stealing code distributed to thousands of applications. ([InfoQ](https://www.infoq.com/news/2026/05/tanstack-supply-chain-attack/))
|
|
10
|
+
- **event-stream (2018)**: Maintainer deliberately added malicious code to steal cryptocurrency wallet keys from Copay users
|
|
11
|
+
- **ua-parser-js (2021)**: Compromised package with cryptomining malware affecting millions of downloads
|
|
12
|
+
- **Colors.js / Faker.js (2022)**: Maintainer intentionally sabotaged popular packages
|
|
13
|
+
|
|
14
|
+
These attacks succeed because:
|
|
15
|
+
- Developers trust npm packages without verification
|
|
16
|
+
- No automated scanning before install
|
|
17
|
+
- Obfuscated code hides malicious intent
|
|
18
|
+
- Typosquatting confuses developers
|
|
19
|
+
|
|
20
|
+
**npm-scan** was built to automatically detect these threats before they reach your project.
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
### Pre-Install Scanning
|
|
25
|
+
- ā
**Blocklist Check** - Known malicious packages (event-stream, flatmap-stream, etc.)
|
|
26
|
+
- ā
**Typosquatting Detection** - Similar names to popular packages (lodash vs lodsh)
|
|
27
|
+
- ā
**Vulnerability Database Check**
|
|
28
|
+
- OSV (Google's Open Source Vulnerabilities)
|
|
29
|
+
- GitHub Advisory Database
|
|
30
|
+
- npm Audit
|
|
31
|
+
- ā
**License Risk Analysis** - Warns about GPL, proprietary, or missing licenses
|
|
32
|
+
- ā
**Maintainer Trust Scoring** - Identifies known trusted maintainers
|
|
33
|
+
- ā
**Repository Validation** - Verifies repo URL matches package
|
|
34
|
+
- ā
**Package Integrity** - Hash verification from npm registry
|
|
35
|
+
- ā
**Size Anomaly Detection** - Flags packages > 50MB
|
|
36
|
+
- ā
**Deprecated Dependencies** - Warns about request, moment, underscore
|
|
37
|
+
|
|
38
|
+
### Post-Install Scanning
|
|
39
|
+
- ā
**Obfuscation Detection** - base64, eval(), hex encoding
|
|
40
|
+
- ā
**Malicious Pattern Detection** - env exfil, shell exec, crypto mining
|
|
41
|
+
- ā
**Suspicious Scripts** - postinstall, preinstall analysis
|
|
42
|
+
- ā
**Sensitive Files** - .env, .ssh, credentials detection
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm install -g npm-scan
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or use without installation:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npx npm-scan pre install <package>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start: Automatic Wrapper
|
|
57
|
+
|
|
58
|
+
The **recommended way** to use npm-scan is with the automatic wrapper:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Install a package with automatic pre + post scan
|
|
62
|
+
npm-scan-wrap install lodash
|
|
63
|
+
|
|
64
|
+
# Install multiple packages
|
|
65
|
+
npm-scan-wrap install lodash axios express
|
|
66
|
+
|
|
67
|
+
# Install all dependencies from package.json
|
|
68
|
+
npm-scan-wrap install
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The wrapper automatically:
|
|
72
|
+
1. š Pre-install scans each package
|
|
73
|
+
2. š„ Runs npm install
|
|
74
|
+
3. š Post-install scans node_modules
|
|
75
|
+
|
|
76
|
+
## Manual Usage
|
|
77
|
+
|
|
78
|
+
If you prefer manual control:
|
|
79
|
+
|
|
80
|
+
### Pre-install scan
|
|
81
|
+
```bash
|
|
82
|
+
npm-scan pre install <package>
|
|
83
|
+
npm-scan pre install axios --version 1.6.0
|
|
84
|
+
npm-scan pre install lodash -V # verbose output
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Post-install scan
|
|
88
|
+
```bash
|
|
89
|
+
npm-scan post
|
|
90
|
+
npm-scan post --folder ./node_modules
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Blocklist management
|
|
94
|
+
```bash
|
|
95
|
+
npm-scan blocklist list
|
|
96
|
+
npm-scan blocklist add <package>
|
|
97
|
+
npm-scan blocklist remove <package>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Detection Patterns
|
|
101
|
+
|
|
102
|
+
### Obfuscation
|
|
103
|
+
- `eval()` with atob/fromCharCode
|
|
104
|
+
- Base64 encoded strings
|
|
105
|
+
- Hex/unicode encoded characters
|
|
106
|
+
|
|
107
|
+
### Malicious Behavior
|
|
108
|
+
- Environment variable access (KEYS, SECRETS, TOKENS)
|
|
109
|
+
- Network requests to IP addresses or external code hosting
|
|
110
|
+
- Child process execution
|
|
111
|
+
- Crypto mining pool connections
|
|
112
|
+
- Keylogging code
|
|
113
|
+
|
|
114
|
+
### Suspicious Scripts
|
|
115
|
+
- postinstall/preinstall with complex shell commands
|
|
116
|
+
- curl/wget downloads
|
|
117
|
+
- Packages scanning directories outside scope
|
|
118
|
+
|
|
119
|
+
## Environment Variables
|
|
120
|
+
|
|
121
|
+
- `GITHUB_TOKEN` - For higher GitHub Advisory API rate limits
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Build
|
|
127
|
+
npm run build
|
|
128
|
+
|
|
129
|
+
# Test
|
|
130
|
+
npm test
|
|
131
|
+
|
|
132
|
+
# Lint
|
|
133
|
+
npm run lint
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Security Threats Detected
|
|
137
|
+
|
|
138
|
+
| Threat Type | Example |
|
|
139
|
+
|------------|---------|
|
|
140
|
+
| Blocklisted | event-stream, flatmap-stream |
|
|
141
|
+
| Typosquatting | lodsh (looks like lodash) |
|
|
142
|
+
| Vulnerabilities | CVE-2021-23337, GHSA-xxxx |
|
|
143
|
+
| Obfuscation | eval(atob(...)) |
|
|
144
|
+
| Malicious Code | process.env.API_KEY exfil |
|
|
145
|
+
| Suspicious Scripts | postinstall: curl ... |
|
|
146
|
+
| Dependency Issues | Deprecated packages, large trees |
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT
|
package/bin/npm-scan
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* npm-scan CLI entry point
|
|
5
|
+
* Pre and post-install security scanner for npm packages
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { run } = require('../dist/cli/index');
|
|
9
|
+
|
|
10
|
+
run(process.argv).catch(err => {
|
|
11
|
+
console.error('npm-scan error:', err.message);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* npm-scan wrapper - Automatically scans before and after npm install
|
|
5
|
+
* Usage: npm-scan-wrap install <packages>
|
|
6
|
+
* npm-scan-wrap install
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { spawn } = require('child_process');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
|
|
13
|
+
const SCANNER_PATH = path.join(__dirname, '../dist/cli/index.js');
|
|
14
|
+
|
|
15
|
+
async function runScanner(args) {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
const scanner = spawn('node', [SCANNER_PATH, ...args], {
|
|
18
|
+
stdio: 'inherit',
|
|
19
|
+
shell: true
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
scanner.on('close', (code) => {
|
|
23
|
+
resolve(code);
|
|
24
|
+
});
|
|
25
|
+
scanner.on('error', reject);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function runNpm(args) {
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
|
32
|
+
const install = spawn(npm, args, {
|
|
33
|
+
stdio: 'inherit',
|
|
34
|
+
shell: true,
|
|
35
|
+
env: { ...process.env, NPM_CONFIG_AUDIT: 'false' }
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
install.on('close', (code) => {
|
|
39
|
+
resolve(code);
|
|
40
|
+
});
|
|
41
|
+
install.on('error', reject);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function main() {
|
|
46
|
+
const args = process.argv.slice(2);
|
|
47
|
+
|
|
48
|
+
if (args.length === 0 || args[0] === 'install') {
|
|
49
|
+
console.log('\nš npm-scan: Running automatic pre-install scan...\n');
|
|
50
|
+
|
|
51
|
+
// Run pre-install scan for all packages being installed
|
|
52
|
+
const packages = args.slice(1);
|
|
53
|
+
|
|
54
|
+
if (packages.length > 0) {
|
|
55
|
+
// Scan each package
|
|
56
|
+
for (const pkg of packages) {
|
|
57
|
+
console.log(`\nš¦ Scanning: ${pkg}\n`);
|
|
58
|
+
await runScanner(['pre', 'install', pkg]);
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
// Scan package.json dependencies
|
|
62
|
+
const pkgJsonPath = path.join(process.cwd(), 'package.json');
|
|
63
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
64
|
+
try {
|
|
65
|
+
const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
|
|
66
|
+
const allDeps = [
|
|
67
|
+
...Object.keys(pkgJson.dependencies || {}),
|
|
68
|
+
...Object.keys(pkgJson.devDependencies || {})
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
console.log(`\nš¦ Scanning ${allDeps.length} dependencies from package.json...\n`);
|
|
72
|
+
|
|
73
|
+
for (const pkg of allDeps) {
|
|
74
|
+
await runScanner(['pre', 'install', pkg]);
|
|
75
|
+
}
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.log('Could not read package.json, skipping dependency scan');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Run npm install
|
|
83
|
+
console.log('\nš„ Running npm install...\n');
|
|
84
|
+
await runNpm(['install', ...args.slice(1)]);
|
|
85
|
+
|
|
86
|
+
// Run post-install scan
|
|
87
|
+
console.log('\nš Running post-install scan...\n');
|
|
88
|
+
await runScanner(['post']);
|
|
89
|
+
|
|
90
|
+
console.log('\nā
npm-scan: Complete!\n');
|
|
91
|
+
} else if (args[0] === 'run') {
|
|
92
|
+
// Just run npm run for scripts
|
|
93
|
+
await runNpm(args);
|
|
94
|
+
} else {
|
|
95
|
+
// Pass through other commands
|
|
96
|
+
await runNpm(args);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point
|
|
3
|
+
* Pre and post-install npm security scanner
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Main CLI runner
|
|
7
|
+
*/
|
|
8
|
+
export declare function run(argv: string[]): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Print help
|
|
11
|
+
*/
|
|
12
|
+
declare function printHelp(): void;
|
|
13
|
+
export { run, printHelp };
|
|
14
|
+
declare const _default: {
|
|
15
|
+
run: typeof run;
|
|
16
|
+
};
|
|
17
|
+
export default _default;
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;GAEG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBvD;AAiRD;;GAEG;AACH,iBAAS,SAAS,IAAI,IAAI,CAyBzB;AAED,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;;;;AAC1B,wBAAuB"}
|