@nikhil_telkar/codeshield 0.0.0-stage → 0.1.1
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/LICENSE +22 -0
- package/README.md +239 -2
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +237 -0
- package/dist/cli.js.map +1 -0
- package/dist/engine/fileWalker.d.ts +15 -0
- package/dist/engine/fileWalker.d.ts.map +1 -0
- package/dist/engine/fileWalker.js +170 -0
- package/dist/engine/fileWalker.js.map +1 -0
- package/dist/engine/index.d.ts +4 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +4 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/projectDetector.d.ts +10 -0
- package/dist/engine/projectDetector.d.ts.map +1 -0
- package/dist/engine/projectDetector.js +44 -0
- package/dist/engine/projectDetector.js.map +1 -0
- package/dist/engine/runner.d.ts +8 -0
- package/dist/engine/runner.d.ts.map +1 -0
- package/dist/engine/runner.js +87 -0
- package/dist/engine/runner.js.map +1 -0
- package/dist/fix/fixer.d.ts +17 -0
- package/dist/fix/fixer.d.ts.map +1 -0
- package/dist/fix/fixer.js +190 -0
- package/dist/fix/fixer.js.map +1 -0
- package/dist/fix/history.d.ts +23 -0
- package/dist/fix/history.d.ts.map +1 -0
- package/dist/fix/history.js +107 -0
- package/dist/fix/history.js.map +1 -0
- package/dist/fix/index.d.ts +3 -0
- package/dist/fix/index.d.ts.map +1 -0
- package/dist/fix/index.js +3 -0
- package/dist/fix/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/report/colors.d.ts +21 -0
- package/dist/report/colors.d.ts.map +1 -0
- package/dist/report/colors.js +70 -0
- package/dist/report/colors.js.map +1 -0
- package/dist/report/index.d.ts +15 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +39 -0
- package/dist/report/index.js.map +1 -0
- package/dist/report/sarif.d.ts +44 -0
- package/dist/report/sarif.d.ts.map +1 -0
- package/dist/report/sarif.js +69 -0
- package/dist/report/sarif.js.map +1 -0
- package/dist/report/score.d.ts +14 -0
- package/dist/report/score.d.ts.map +1 -0
- package/dist/report/score.js +62 -0
- package/dist/report/score.js.map +1 -0
- package/dist/report/terminal.d.ts +10 -0
- package/dist/report/terminal.d.ts.map +1 -0
- package/dist/report/terminal.js +77 -0
- package/dist/report/terminal.js.map +1 -0
- package/dist/scanners/code.d.ts +22 -0
- package/dist/scanners/code.d.ts.map +1 -0
- package/dist/scanners/code.js +319 -0
- package/dist/scanners/code.js.map +1 -0
- package/dist/scanners/dependencies.d.ts +10 -0
- package/dist/scanners/dependencies.d.ts.map +1 -0
- package/dist/scanners/dependencies.js +240 -0
- package/dist/scanners/dependencies.js.map +1 -0
- package/dist/scanners/env.d.ts +7 -0
- package/dist/scanners/env.d.ts.map +1 -0
- package/dist/scanners/env.js +195 -0
- package/dist/scanners/env.js.map +1 -0
- package/dist/scanners/helper.d.ts +27 -0
- package/dist/scanners/helper.d.ts.map +1 -0
- package/dist/scanners/helper.js +50 -0
- package/dist/scanners/helper.js.map +1 -0
- package/dist/scanners/index.d.ts +6 -0
- package/dist/scanners/index.d.ts.map +1 -0
- package/dist/scanners/index.js +6 -0
- package/dist/scanners/index.js.map +1 -0
- package/dist/scanners/secrets.d.ts +19 -0
- package/dist/scanners/secrets.d.ts.map +1 -0
- package/dist/scanners/secrets.js +213 -0
- package/dist/scanners/secrets.js.map +1 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/constants.d.ts +9 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +54 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/levenshtein.d.ts +2 -0
- package/dist/utils/levenshtein.d.ts.map +1 -0
- package/dist/utils/levenshtein.js +35 -0
- package/dist/utils/levenshtein.js.map +1 -0
- package/dist/utils/registry.d.ts +18 -0
- package/dist/utils/registry.d.ts.map +1 -0
- package/dist/utils/registry.js +106 -0
- package/dist/utils/registry.js.map +1 -0
- package/dist/utils/sanitize.d.ts +3 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +10 -0
- package/dist/utils/sanitize.js.map +1 -0
- package/package.json +59 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nikhil Telkar
|
|
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, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
CHANGED
|
@@ -1,3 +1,240 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CodeShield
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **A fast, zero-dependency security scanner for AI-generated codebases.**
|
|
4
|
+
|
|
5
|
+
AI coding assistants (Cursor, Copilot, ChatGPT, Claude, v0, Bolt) are extraordinary at writing code quickly, but they frequently introduce dangerous security flaws: hardcoding API keys, hallucinating nonexistent npm packages, writing SQL queries with string concatenation, using `Math.random()` for auth tokens, or forgetting basic security headers like `helmet`.
|
|
6
|
+
|
|
7
|
+
**CodeShield** acts as an instant security guardrail for your development workflow and CI/CD pipelines.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ⚡ 30-Second Quick Start
|
|
12
|
+
|
|
13
|
+
No installation required. Run directly with `npx`:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Scan current project
|
|
17
|
+
npx @nikhil_telkar/codeshield scan .
|
|
18
|
+
|
|
19
|
+
# Automatically apply safe fixes (.gitignore, .env.example)
|
|
20
|
+
npx @nikhil_telkar/codeshield fix .
|
|
21
|
+
|
|
22
|
+
# Check if an npm package is real, safe, or an AI hallucination
|
|
23
|
+
npx @nikhil_telkar/codeshield verify express
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or install globally to use the short `codeshield` command anywhere:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install -g @nikhil_telkar/codeshield
|
|
30
|
+
codeshield scan .
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 🖥️ Clean, Developer-Friendly Terminal Output
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
CodeShield — scanning /Users/dev/my-ai-app
|
|
39
|
+
(offline mode: npm registry checks skipped)
|
|
40
|
+
|
|
41
|
+
────────────────────────────────────────────────────────────
|
|
42
|
+
Security Score : 54/100 [Grade C] (Needs Attention)
|
|
43
|
+
Files Scanned : 42 files
|
|
44
|
+
Findings : 3 [1 critical, 1 high, 1 medium]
|
|
45
|
+
Duration : 28ms
|
|
46
|
+
────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
🎯 Fix These First (Top Priorities):
|
|
49
|
+
|
|
50
|
+
🔴 CRITICAL [SEC-001] Hardcoded AWS Access Key
|
|
51
|
+
File : src/config/aws.ts:14
|
|
52
|
+
Line : AWS_ACCESS_KEY_ID=AKIA****
|
|
53
|
+
Issue : An AWS Access Key ID was found directly in your code. Anyone with access to this repo can compromise your AWS account.
|
|
54
|
+
Fix : Move credentials to process.env.AWS_ACCESS_KEY_ID or use IAM roles.
|
|
55
|
+
AI Prompt : Refactor src/config/aws.ts to load AWS credentials from process.env.AWS_ACCESS_KEY_ID.
|
|
56
|
+
|
|
57
|
+
🟠 HIGH [COD-002] SQL Query Built via String Concatenation (SQL Injection)
|
|
58
|
+
File : src/routes/users.ts:28
|
|
59
|
+
Line : const query = "SELECT * FROM users WHERE id = '" + req.query.id + "'";
|
|
60
|
+
Issue : Constructing SQL queries using template literals or string concatenation allows SQL Injection.
|
|
61
|
+
Fix : Use parameterized queries (e.g., db.query("SELECT * FROM users WHERE id = $1", [id])).
|
|
62
|
+
AI Prompt : Refactor the SQL query on line 28 to use parameterized queries with placeholders.
|
|
63
|
+
|
|
64
|
+
🟡 MEDIUM [COD-011] Missing Security Headers Middleware (Helmet) in Express App
|
|
65
|
+
File : src/server.ts:1
|
|
66
|
+
Issue : Express application initialized without helmet() security headers middleware.
|
|
67
|
+
Fix : Install helmet (`npm install helmet`) and add `app.use(helmet())` near the top of your Express middleware stack.
|
|
68
|
+
AI Prompt : Import `helmet` from "helmet" and add `app.use(helmet())` right after initializing the Express application.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 🔍 What CodeShield Checks
|
|
74
|
+
|
|
75
|
+
CodeShield evaluates codebases across four core dimensions with **zero runtime dependencies**:
|
|
76
|
+
|
|
77
|
+
### 1. Secrets Scanner
|
|
78
|
+
- **AWS Credentials:** Hardcoded `AKIA...` access keys (`CWE-798`).
|
|
79
|
+
- **Stripe Keys:** Live API keys (`sk_live_...`) (`CWE-798`).
|
|
80
|
+
- **GitHub Tokens:** Personal access tokens (`ghp_...`, `github_pat_...`) (`CWE-798`).
|
|
81
|
+
- **AI Provider API Keys:** OpenAI (`sk-...`), Anthropic (`sk-ant-...`) keys (`CWE-798`).
|
|
82
|
+
- **Supabase Service Keys:** Hardcoded `service_role` administrative keys (`CWE-798`).
|
|
83
|
+
- **Database Connection Strings:** URLs containing embedded passwords (`postgres://user:pass@host/db`) (`CWE-256`).
|
|
84
|
+
- **Private Key Headers:** Unencrypted PEM blocks (`BEGIN RSA/OPENSSH PRIVATE KEY`) (`CWE-312`).
|
|
85
|
+
- **Hardcoded JWT Secrets:** Literal strings passed to `jwt.sign()` (`CWE-798`).
|
|
86
|
+
- **Generic API Credentials:** High-entropy API key and token assignments (`CWE-798`).
|
|
87
|
+
- **Public Client Leaks:** Private keys placed in `NEXT_PUBLIC_*` or `VITE_*` variables (`CWE-200`).
|
|
88
|
+
|
|
89
|
+
### 2. Dependency Scanner (AI Hallucination Guard)
|
|
90
|
+
- **Hallucinated Packages (DEP-001):** Verifies all dependencies in `package.json` against the npm registry to catch non-existent packages invented by AI tools (`CWE-829`).
|
|
91
|
+
- **Newly Published Packages (DEP-002):** Warns if dependencies were published $< 30$ days ago (`CWE-829`).
|
|
92
|
+
- **Install Scripts (DEP-003):** Flags packages that run `preinstall`, `install`, or `postinstall` shell scripts (`CWE-829`).
|
|
93
|
+
- **Typosquatting (DEP-004):** Detects packages that are 1 character away from popular libraries (`expres`, `lodahs`) (`CWE-829`).
|
|
94
|
+
|
|
95
|
+
### 3. Environment & Config Scanner
|
|
96
|
+
- **Unignored `.env` Files:** Credentials exposed to git tracking (`CWE-552`).
|
|
97
|
+
- **Missing `.env.example`:** Repositories with `.env` but no sanitized template for collaborators (`CWE-552`).
|
|
98
|
+
- **Production Source Maps:** `productionBrowserSourceMaps: true` or `sourcemap: true` leaking unminified code in production (`CWE-540`).
|
|
99
|
+
|
|
100
|
+
### 4. Code Pattern Scanner
|
|
101
|
+
- **Dynamic Code Execution:** `eval()` and `new Function()` (`CWE-95`).
|
|
102
|
+
- **SQL Injection:** String concatenation in `db.query()`, `prisma.$queryRawUnsafe()`, etc. (`CWE-89`).
|
|
103
|
+
- **NoSQL Injection:** Raw `req.body` or `req.query` passed directly into MongoDB/Mongoose queries (`CWE-943`).
|
|
104
|
+
- **Command Injection:** `child_process.exec()` called with variables (`CWE-78`).
|
|
105
|
+
- **Insecure Randomness:** `Math.random()` used for tokens, passwords, or session IDs (`CWE-338`).
|
|
106
|
+
- **Broken Cryptography:** MD5 or SHA-1 used for password hashing (`CWE-328`).
|
|
107
|
+
- **Cross-Site Scripting (XSS):** `dangerouslySetInnerHTML` or `element.innerHTML` with dynamic variables (`CWE-79`).
|
|
108
|
+
- **Permissive CORS:** `cors({ origin: '*' })` (`CWE-942`).
|
|
109
|
+
- **Insecure Cookies:** `res.cookie()` without `httpOnly: true` or `secure: true` (`CWE-1004`, `CWE-614`).
|
|
110
|
+
- **Indefinite JWTs:** `jwt.sign()` calls missing an `expiresIn` option (`CWE-613`).
|
|
111
|
+
- **Missing Helmet:** Express applications without `helmet` security header middleware (`CWE-693`).
|
|
112
|
+
- **Stack Trace Leakage:** Returning `err.stack` in HTTP responses (`CWE-209`).
|
|
113
|
+
- **Client-Side Supabase Admin:** Using Supabase `service_role` keys inside frontend components (`CWE-200`).
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 🛠️ CLI Commands & Options
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
Usage:
|
|
121
|
+
codeshield scan [path] [options] Scan directory (default: current dir)
|
|
122
|
+
codeshield fix [path] [--yes] Apply safe, reversible fixes automatically
|
|
123
|
+
codeshield verify <package> Check a single npm package
|
|
124
|
+
codeshield --help Show this help
|
|
125
|
+
codeshield --version Show version
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Scan Options
|
|
129
|
+
|
|
130
|
+
| Option | Description |
|
|
131
|
+
| :--- | :--- |
|
|
132
|
+
| `--detailed` | Show full metadata for all findings (CWE, rule ID, file, line, explanation). |
|
|
133
|
+
| `--json` | Output machine-readable JSON (ideal for CI pipelines). |
|
|
134
|
+
| `--sarif` | Output static analysis results in SARIF v2.1.0 format (for GitHub Security). |
|
|
135
|
+
| `--fail-on <severity>` | Set exit code to 1 if any findings match or exceed `<severity>` (`critical`, `high`, `medium`, `low`, `info`). Default: `info`. |
|
|
136
|
+
| `--severity <severity>` | Filter the report to only include findings at or above `<severity>`. Default: `info`. |
|
|
137
|
+
| `--offline` | Skip all npm registry lookups (runs purely offline in $< 50\text{ms}$). |
|
|
138
|
+
|
|
139
|
+
### Fix Options
|
|
140
|
+
|
|
141
|
+
| Option | Description |
|
|
142
|
+
| :--- | :--- |
|
|
143
|
+
| `-y, --yes` | Apply safe fixes automatically without an interactive prompt. |
|
|
144
|
+
|
|
145
|
+
*Safety guarantee:* `codeshield fix` only applies reversible, non-destructive changes (`.gitignore` additions, creating `.env.example`). It creates `.codeshield.bak` backups before modifying files and never writes outside the scan root.
|
|
146
|
+
|
|
147
|
+
### Exit Codes
|
|
148
|
+
|
|
149
|
+
| Code | Meaning |
|
|
150
|
+
| :---: | :--- |
|
|
151
|
+
| `0` | **Passed:** No findings at or above the `--fail-on` threshold. |
|
|
152
|
+
| `1` | **Failed:** One or more findings detected at or above the `--fail-on` threshold. |
|
|
153
|
+
| `2` | **Tool Error:** Invalid CLI arguments, missing files, or unreadable directory. |
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 📊 How the Security Score Works
|
|
158
|
+
|
|
159
|
+
CodeShield calculates an objective score between **0 and 100**:
|
|
160
|
+
|
|
161
|
+
$$\text{Score} = \max\left(0, 100 - \sum \text{Capped Deductions}\right)$$
|
|
162
|
+
|
|
163
|
+
### Severity Weights & Deductions
|
|
164
|
+
|
|
165
|
+
| Severity | Points Deducted per Finding | Maximum Deductions per Rule |
|
|
166
|
+
| :--- | :---: | :---: |
|
|
167
|
+
| **Critical** | -25 | Capped at -35 max per rule |
|
|
168
|
+
| **High** | -15 | Capped at -35 max per rule |
|
|
169
|
+
| **Medium** | -8 | Capped at -35 max per rule |
|
|
170
|
+
| **Low** | -3 | Capped at -35 max per rule |
|
|
171
|
+
| **Info** | 0 | 0 |
|
|
172
|
+
|
|
173
|
+
### Anti-Noise Rule Capping
|
|
174
|
+
To prevent a single repetitive issue (such as 50 missing cookie flags) from zeroing out the entire score, deductions for any single rule are capped at **35 points**.
|
|
175
|
+
|
|
176
|
+
### Grade Scale
|
|
177
|
+
- **90–100 [Grade A]** — Excellent: Clean security posture.
|
|
178
|
+
- **75–89 [Grade B]** — Good: Minor low/medium issues.
|
|
179
|
+
- **60–74 [Grade C]** — Needs Attention: High-risk findings present.
|
|
180
|
+
- **40–59 [Grade D]** — Poor: Multiple severe vulnerabilities.
|
|
181
|
+
- **0–39 [Grade F]** — Critical: Immediate attention required.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 🤖 CI / CD Integration
|
|
186
|
+
|
|
187
|
+
Add `.github/workflows/security.yml`:
|
|
188
|
+
|
|
189
|
+
```yaml
|
|
190
|
+
name: CodeShield Security Scan
|
|
191
|
+
|
|
192
|
+
on:
|
|
193
|
+
push:
|
|
194
|
+
branches: [main]
|
|
195
|
+
pull_request:
|
|
196
|
+
branches: [main]
|
|
197
|
+
|
|
198
|
+
jobs:
|
|
199
|
+
scan:
|
|
200
|
+
runs-on: ubuntu-latest
|
|
201
|
+
steps:
|
|
202
|
+
- name: Checkout repository
|
|
203
|
+
uses: actions/checkout@v4
|
|
204
|
+
|
|
205
|
+
- name: Set up Node.js
|
|
206
|
+
uses: actions/setup-node@v4
|
|
207
|
+
with:
|
|
208
|
+
node-version: '20'
|
|
209
|
+
|
|
210
|
+
# Option A: Fail the build on high/critical findings
|
|
211
|
+
- name: Run CodeShield Scan
|
|
212
|
+
run: npx @nikhil_telkar/codeshield scan . --fail-on high
|
|
213
|
+
|
|
214
|
+
# Option B: Upload SARIF report to GitHub Advanced Security tab
|
|
215
|
+
- name: Generate SARIF report
|
|
216
|
+
if: always()
|
|
217
|
+
run: npx @nikhil_telkar/codeshield scan . --sarif > results.sarif
|
|
218
|
+
|
|
219
|
+
- name: Upload SARIF to GitHub Code Scanning
|
|
220
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
221
|
+
if: always()
|
|
222
|
+
with:
|
|
223
|
+
sarif_file: results.sarif
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## 🔒 Privacy & Security Statement
|
|
229
|
+
|
|
230
|
+
- **100% Local Execution:** CodeShield never uploads your source code, filenames, or directory paths to external servers.
|
|
231
|
+
- **Zero Telemetry:** No analytics, no phone-home pings, no cookies, no tracking.
|
|
232
|
+
- **Zero Runtime Dependencies:** Zero third-party packages installed in production. Zero supply chain risk.
|
|
233
|
+
- **Strict Read-Only Scanning:** CodeShield inspects text files using Node built-in file APIs. It **never** dynamically evaluates, requires, or imports your code.
|
|
234
|
+
- **Optional Network Access:** The only network request CodeShield can make is an HTTPS query to `https://registry.npmjs.org/<package>` to verify npm packages during `codeshield verify` or standard scans. Pass `--offline` to run completely disconnected.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 📄 License
|
|
239
|
+
|
|
240
|
+
[MIT](LICENSE) © 2026 Nikhil Telkar
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA4LA,wBAAsB,MAAM,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAyFpF"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { parseArgs } from 'node:util';
|
|
6
|
+
import { secretsScanner } from './scanners/secrets.js';
|
|
7
|
+
import { envScanner } from './scanners/env.js';
|
|
8
|
+
import { codeScanner } from './scanners/code.js';
|
|
9
|
+
import { fetchRegistry } from './utils/registry.js';
|
|
10
|
+
import { isValidNpmName } from './scanners/dependencies.js';
|
|
11
|
+
import { runScanAsync } from './engine/runner.js';
|
|
12
|
+
import { SEVERITY_RANK, SEVERITIES } from './utils/constants.js';
|
|
13
|
+
import { sanitize } from './utils/sanitize.js';
|
|
14
|
+
import { renderReport, calculateScore } from './report/index.js';
|
|
15
|
+
import { runFix } from './fix/fixer.js';
|
|
16
|
+
import { readLastScan, saveLastScan, compareWithLastScan } from './fix/history.js';
|
|
17
|
+
function getVersion() {
|
|
18
|
+
try {
|
|
19
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const pkgPath = resolve(currentDir, '..', 'package.json');
|
|
21
|
+
const content = readFileSync(pkgPath, 'utf8');
|
|
22
|
+
const parsed = JSON.parse(content);
|
|
23
|
+
return parsed.version ?? '0.1.0';
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return '0.1.0';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function isValidSeverity(s) {
|
|
30
|
+
return SEVERITIES.includes(s);
|
|
31
|
+
}
|
|
32
|
+
const HELP_TEXT = `
|
|
33
|
+
CodeShield — Security scanner for AI-generated codebases
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
codeshield scan [path] [options] Scan directory (default: current dir)
|
|
37
|
+
codeshield fix [path] [--yes] Apply safe, reversible fixes automatically
|
|
38
|
+
codeshield verify <package> Check a single npm package
|
|
39
|
+
codeshield --help Show this help
|
|
40
|
+
codeshield --version Show version
|
|
41
|
+
|
|
42
|
+
Scan options:
|
|
43
|
+
--detailed Show all findings with full metadata
|
|
44
|
+
--json Output results as JSON (for CI)
|
|
45
|
+
--sarif Output results as SARIF v2.1.0
|
|
46
|
+
--fail-on <severity> Exit code 1 if findings >= severity
|
|
47
|
+
(critical|high|medium|low|info, default: info)
|
|
48
|
+
--severity <severity> Minimum severity to include in report
|
|
49
|
+
(critical|high|medium|low|info, default: info)
|
|
50
|
+
--offline Skip npm registry network checks
|
|
51
|
+
|
|
52
|
+
Fix options:
|
|
53
|
+
-y, --yes Skip confirmation prompt and apply fixes
|
|
54
|
+
|
|
55
|
+
Examples:
|
|
56
|
+
codeshield scan .
|
|
57
|
+
codeshield scan ./my-project --detailed
|
|
58
|
+
codeshield scan . --fail-on high
|
|
59
|
+
codeshield scan . --json
|
|
60
|
+
codeshield scan . --sarif > results.sarif
|
|
61
|
+
codeshield fix .
|
|
62
|
+
codeshield fix ./my-project --yes
|
|
63
|
+
codeshield verify express
|
|
64
|
+
|
|
65
|
+
Exit codes:
|
|
66
|
+
0 Passed (no findings at or above fail-on threshold)
|
|
67
|
+
1 Findings detected at or above fail-on threshold
|
|
68
|
+
2 Tool error
|
|
69
|
+
`.trim();
|
|
70
|
+
async function runVerify(pkgName) {
|
|
71
|
+
const safeName = sanitize(pkgName);
|
|
72
|
+
if (!isValidNpmName(pkgName)) {
|
|
73
|
+
console.error(`Error: "${safeName}" is not a valid npm package name.`);
|
|
74
|
+
return 2;
|
|
75
|
+
}
|
|
76
|
+
console.log(`Checking "${safeName}" on npm registry…`);
|
|
77
|
+
const result = await fetchRegistry(pkgName, 5_000);
|
|
78
|
+
if (result.status === 'not-found') {
|
|
79
|
+
console.log(`\n🔴 CRITICAL [DEP-001] Package does not exist on npm.`);
|
|
80
|
+
console.log(` "${safeName}" was not found in the npm registry.`);
|
|
81
|
+
console.log(` This may be a hallucinated package name from an AI tool.`);
|
|
82
|
+
console.log(` Verify at https://www.npmjs.com/package/${safeName}`);
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
85
|
+
if (result.status === 'error') {
|
|
86
|
+
console.error(`\n⚠️ Could not check "${safeName}": ${sanitize(result.reason)}`);
|
|
87
|
+
console.error(` The package has NOT been verified as safe.`);
|
|
88
|
+
return 2;
|
|
89
|
+
}
|
|
90
|
+
const { data } = result;
|
|
91
|
+
const thirtyDaysMs = 30 * 24 * 60 * 60 * 1000;
|
|
92
|
+
let hasFindings = false;
|
|
93
|
+
console.log(`\n✅ Package "${safeName}" exists on npm.`);
|
|
94
|
+
if (data.created) {
|
|
95
|
+
console.log(` First published : ${data.created}`);
|
|
96
|
+
if (Date.now() - Date.parse(data.created) < thirtyDaysMs) {
|
|
97
|
+
console.log(` 🟠 HIGH [DEP-002] Published less than 30 days ago — verify this is intentional.`);
|
|
98
|
+
hasFindings = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const dangerScripts = ['install', 'postinstall', 'preinstall'].filter((s) => s in data.latestScripts);
|
|
102
|
+
if (dangerScripts.length > 0) {
|
|
103
|
+
console.log(` 🟠 HIGH [DEP-003] Has install script(s): ${dangerScripts.join(', ')}`);
|
|
104
|
+
console.log(` Audit the script source before installing.`);
|
|
105
|
+
hasFindings = true;
|
|
106
|
+
}
|
|
107
|
+
if (!hasFindings) {
|
|
108
|
+
console.log(` No issues found. Always review packages before use.`);
|
|
109
|
+
}
|
|
110
|
+
return hasFindings ? 1 : 0;
|
|
111
|
+
}
|
|
112
|
+
async function runScan(opts) {
|
|
113
|
+
const root = resolve(opts.targetPath);
|
|
114
|
+
const isStructuredOutput = opts.mode === 'json' || opts.mode === 'sarif';
|
|
115
|
+
if (!isStructuredOutput) {
|
|
116
|
+
console.log(`CodeShield — scanning ${root}`);
|
|
117
|
+
if (opts.offline)
|
|
118
|
+
console.log('(offline mode: npm registry checks skipped)');
|
|
119
|
+
}
|
|
120
|
+
let result;
|
|
121
|
+
try {
|
|
122
|
+
result = await runScanAsync({
|
|
123
|
+
root,
|
|
124
|
+
minSeverity: opts.minSeverity,
|
|
125
|
+
scanners: [secretsScanner, envScanner, codeScanner],
|
|
126
|
+
depOptions: { offline: opts.offline },
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
131
|
+
console.error(`Error during scan: ${sanitize(msg)}`);
|
|
132
|
+
return 2;
|
|
133
|
+
}
|
|
134
|
+
const scoreDetails = calculateScore(result.findings);
|
|
135
|
+
const previousScan = readLastScan(root);
|
|
136
|
+
let historyText;
|
|
137
|
+
if (previousScan) {
|
|
138
|
+
const comparison = compareWithLastScan(previousScan, scoreDetails.score, result.findings);
|
|
139
|
+
historyText = comparison.summaryText;
|
|
140
|
+
}
|
|
141
|
+
saveLastScan(root, scoreDetails.score, scoreDetails.grade, result.findings);
|
|
142
|
+
const output = renderReport(result, {
|
|
143
|
+
mode: opts.mode,
|
|
144
|
+
version: getVersion(),
|
|
145
|
+
...(historyText ? { historyText } : {}),
|
|
146
|
+
});
|
|
147
|
+
console.log(output);
|
|
148
|
+
const failOnRank = SEVERITY_RANK[opts.failOn] ?? 0;
|
|
149
|
+
const hasFailingFindings = result.findings.some((f) => (SEVERITY_RANK[f.severity] ?? 0) >= failOnRank);
|
|
150
|
+
return hasFailingFindings ? 1 : 0;
|
|
151
|
+
}
|
|
152
|
+
export async function runCli(argv = process.argv.slice(2)) {
|
|
153
|
+
try {
|
|
154
|
+
const { values, positionals } = parseArgs({
|
|
155
|
+
args: argv,
|
|
156
|
+
options: {
|
|
157
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
158
|
+
version: { type: 'boolean', short: 'v', default: false },
|
|
159
|
+
offline: { type: 'boolean', default: false },
|
|
160
|
+
detailed: { type: 'boolean', default: false },
|
|
161
|
+
json: { type: 'boolean', default: false },
|
|
162
|
+
sarif: { type: 'boolean', default: false },
|
|
163
|
+
yes: { type: 'boolean', short: 'y', default: false },
|
|
164
|
+
severity: { type: 'string', default: 'info' },
|
|
165
|
+
'fail-on': { type: 'string' },
|
|
166
|
+
},
|
|
167
|
+
allowPositionals: true,
|
|
168
|
+
strict: true,
|
|
169
|
+
});
|
|
170
|
+
if (values.version) {
|
|
171
|
+
console.log(`codeshield v${getVersion()}`);
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
if (values.help || positionals.length === 0) {
|
|
175
|
+
console.log(HELP_TEXT);
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
const severityArg = values.severity ?? 'info';
|
|
179
|
+
if (!isValidSeverity(severityArg)) {
|
|
180
|
+
console.error(`Error: Invalid severity "${sanitize(severityArg)}". ` +
|
|
181
|
+
`Valid values: ${SEVERITIES.join(', ')}`);
|
|
182
|
+
return 2;
|
|
183
|
+
}
|
|
184
|
+
const failOnArg = values['fail-on'] ?? severityArg;
|
|
185
|
+
if (!isValidSeverity(failOnArg)) {
|
|
186
|
+
console.error(`Error: Invalid fail-on severity "${sanitize(failOnArg)}". ` +
|
|
187
|
+
`Valid values: ${SEVERITIES.join(', ')}`);
|
|
188
|
+
return 2;
|
|
189
|
+
}
|
|
190
|
+
let mode = 'simple';
|
|
191
|
+
if (values.json)
|
|
192
|
+
mode = 'json';
|
|
193
|
+
else if (values.sarif)
|
|
194
|
+
mode = 'sarif';
|
|
195
|
+
else if (values.detailed)
|
|
196
|
+
mode = 'detailed';
|
|
197
|
+
const command = positionals[0];
|
|
198
|
+
if (command === 'scan') {
|
|
199
|
+
const targetPath = positionals[1] ?? '.';
|
|
200
|
+
return await runScan({
|
|
201
|
+
targetPath,
|
|
202
|
+
offline: values.offline ?? false,
|
|
203
|
+
minSeverity: severityArg,
|
|
204
|
+
failOn: failOnArg,
|
|
205
|
+
mode,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
if (command === 'fix') {
|
|
209
|
+
const targetPath = positionals[1] ?? '.';
|
|
210
|
+
return await runFix(targetPath, values.yes ?? false);
|
|
211
|
+
}
|
|
212
|
+
if (command === 'verify') {
|
|
213
|
+
const pkgName = positionals[1];
|
|
214
|
+
if (!pkgName) {
|
|
215
|
+
console.error('Error: "verify" requires a package name. Example: codeshield verify express');
|
|
216
|
+
return 2;
|
|
217
|
+
}
|
|
218
|
+
return await runVerify(pkgName);
|
|
219
|
+
}
|
|
220
|
+
console.error(`Error: Unknown command "${sanitize(command)}". Run "codeshield --help" for available commands.`);
|
|
221
|
+
return 2;
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
225
|
+
console.error(`Error: ${sanitize(message)}`);
|
|
226
|
+
return 2;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const isDirectlyExecuted = process.argv[1] !== undefined &&
|
|
230
|
+
(process.argv[1] === fileURLToPath(import.meta.url) ||
|
|
231
|
+
process.argv[1].endsWith('/codeshield') ||
|
|
232
|
+
process.argv[1].endsWith('\\codeshield'));
|
|
233
|
+
if (isDirectlyExecuted) {
|
|
234
|
+
const exitCode = await runCli();
|
|
235
|
+
process.exit(exitCode);
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ScannedFile } from '../types.js';
|
|
2
|
+
export interface FileWalkerOptions {
|
|
3
|
+
root: string;
|
|
4
|
+
maxFiles?: number;
|
|
5
|
+
maxBytes?: number;
|
|
6
|
+
onSkip?: (filePath: string, reason: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface FileWalkerResult {
|
|
9
|
+
files: ScannedFile[];
|
|
10
|
+
filesVisited: number;
|
|
11
|
+
filesSkipped: number;
|
|
12
|
+
truncated: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function walkFiles(root: string, options?: Partial<FileWalkerOptions>): FileWalkerResult;
|
|
15
|
+
//# sourceMappingURL=fileWalker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileWalker.d.ts","sourceRoot":"","sources":["../../src/engine/fileWalker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAS1C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,OAAO,CAAC,iBAAiB,CAAM,GAAG,gBAAgB,CAkLlG"}
|