@lhi/tdd-audit 1.16.0 → 1.18.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/README.md +85 -39
- package/SKILL.md +6 -0
- package/docs/ai-remediation.md +114 -42
- package/docs/rest-api.md +144 -131
- package/docs/scanner.md +5 -3
- package/docs/vulnerability-patterns.md +241 -1
- package/index.js +37 -26
- package/lib/auditor.js +879 -0
- package/lib/badge.js +13 -6
- package/lib/config.js +12 -0
- package/lib/plugin.js +118 -23
- package/lib/reporter.js +6 -3
- package/lib/scanner.js +29 -0
- package/package.json +1 -1
- package/prompts/ai-security.md +329 -0
- package/prompts/auto-audit.md +270 -12
- package/prompts/node-advanced-security.md +394 -0
package/docs/rest-api.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# REST API
|
|
2
2
|
|
|
3
|
-
`tdd-audit serve`
|
|
3
|
+
`tdd-audit serve` exposes an authenticated HTTP API built on **Fastify**. Use it to integrate AI-powered security audits into dashboards, CI pipelines, bots, or any tooling that speaks JSON.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -59,7 +59,7 @@ By default the rate limiter keys on the **socket IP**, not `X-Forwarded-For`, to
|
|
|
59
59
|
|
|
60
60
|
### Path validation
|
|
61
61
|
|
|
62
|
-
`POST /
|
|
62
|
+
`POST /audit` and `POST /audit/ai` validate that the requested path is inside the server's working directory. The check is normalised with a trailing path separator to prevent sibling-directory prefix bypasses (e.g. `/app-evil` cannot escape via `/app`). Paths outside cwd return `400`.
|
|
63
63
|
|
|
64
64
|
### Security headers
|
|
65
65
|
|
|
@@ -80,60 +80,117 @@ X-Frame-Options: DENY
|
|
|
80
80
|
No auth required. Returns server status and version.
|
|
81
81
|
|
|
82
82
|
```json
|
|
83
|
-
{ "status": "ok", "version": "1.
|
|
83
|
+
{ "status": "ok", "version": "1.17.0" }
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
---
|
|
87
87
|
|
|
88
|
-
### `POST /
|
|
88
|
+
### `POST /audit/ai`
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
**The primary endpoint.** Runs a full agentic LLM audit using tool calls (`read_file`, `list_files`, `search_in_files`, `write_file`). Returns immediately with a `jobId`; poll `GET /jobs/:id` or stream `GET /jobs/:id/stream` for results.
|
|
91
|
+
|
|
92
|
+
Provider and API key can be supplied in the request body or pre-configured in `.tdd-audit.json`.
|
|
91
93
|
|
|
92
94
|
**Request**
|
|
93
95
|
```json
|
|
94
96
|
{
|
|
95
|
-
"path":
|
|
96
|
-
"
|
|
97
|
+
"path": ".",
|
|
98
|
+
"provider": "anthropic",
|
|
99
|
+
"apiKey": "sk-ant-...",
|
|
100
|
+
"model": "claude-opus-4-6",
|
|
101
|
+
"baseUrl": null,
|
|
102
|
+
"depth": "tier-2"
|
|
97
103
|
}
|
|
98
104
|
```
|
|
99
105
|
|
|
100
|
-
| Field |
|
|
106
|
+
| Field | Required | Default | Description |
|
|
101
107
|
|---|---|---|---|
|
|
102
|
-
| `path` |
|
|
103
|
-
| `
|
|
108
|
+
| `path` | no | cwd | Path to audit. Must be inside server cwd. |
|
|
109
|
+
| `provider` | yes* | cfg | `anthropic` \| `openai` \| `gemini` \| `ollama` |
|
|
110
|
+
| `apiKey` | yes* | cfg | Provider API key |
|
|
111
|
+
| `model` | no | provider default | Model override |
|
|
112
|
+
| `baseUrl` | no | — | Base URL for OpenAI-compatible services |
|
|
113
|
+
| `depth` | no | `tier-1` | Output depth tier (see below) |
|
|
114
|
+
| `scanOnly` | no | — | Override depth-derived scan mode |
|
|
115
|
+
| `allowWrites` | no | `false` | Override depth-derived write permission |
|
|
116
|
+
| `findings` | no | — | Pre-identified findings array (triggers targeted-apply mode when `depth=tier-4`) |
|
|
117
|
+
|
|
118
|
+
*Required unless configured in `.tdd-audit.json`.
|
|
119
|
+
|
|
120
|
+
**Response — 202 Accepted**
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
HTTP/1.1 202 Accepted
|
|
124
|
+
Location: /jobs/job_1_...
|
|
125
|
+
Retry-After: 5
|
|
126
|
+
```
|
|
127
|
+
```json
|
|
128
|
+
{ "jobId": "job_1_1711363200000" }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Job result envelope** (available via `GET /jobs/:id` after completion)
|
|
104
132
|
|
|
105
|
-
**Response — JSON**
|
|
106
133
|
```json
|
|
107
134
|
{
|
|
108
|
-
"version":
|
|
109
|
-
"
|
|
110
|
-
"
|
|
135
|
+
"version": "1.16.0",
|
|
136
|
+
"provider": "anthropic",
|
|
137
|
+
"model": "claude-opus-4-6",
|
|
138
|
+
"depth": "tier-2",
|
|
139
|
+
"mode": "scan-only",
|
|
140
|
+
"stack": "Node.js / Express",
|
|
141
|
+
"summary": { "CRITICAL": 1, "HIGH": 2, "MEDIUM": 0, "LOW": 1 },
|
|
142
|
+
"patchesApplied": 0,
|
|
143
|
+
"findings": [ ... ],
|
|
111
144
|
"likelyFalsePositives": [ ... ],
|
|
112
|
-
"
|
|
113
|
-
"scannedAt":
|
|
114
|
-
"duration": 42
|
|
145
|
+
"remediation": [],
|
|
146
|
+
"scannedAt": "2026-03-26T12:00:00.000Z"
|
|
115
147
|
}
|
|
116
148
|
```
|
|
117
149
|
|
|
118
|
-
|
|
150
|
+
`patchesApplied` is the billable unit for `tier-4`: the count of `remediation` entries where `status === "fixed"`.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### Depth tiers
|
|
155
|
+
|
|
156
|
+
| Tier | Mode | Finding fields added | `allowWrites` |
|
|
157
|
+
|---|---|---|---|
|
|
158
|
+
| `tier-1` | scan-only | `name`, `severity`, `file`, `line`, `snippet` | no |
|
|
159
|
+
| `tier-2` | scan-only | + `risk`, `effort`, `cwe`, `owasp`, `references` | no |
|
|
160
|
+
| `tier-3` | full audit | + `patch` (copy-ready), `testSnippet` | no |
|
|
161
|
+
| `tier-4` | full audit | LLM calls `write_file`; `remediation` array tracks each patch | yes |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### Targeted apply (tier-4 + findings)
|
|
119
166
|
|
|
120
|
-
|
|
167
|
+
When `depth=tier-4` and a `findings` array is supplied, the LLM skips the scan phase entirely and applies only the patches you specify. Use this to apply a single finding from a previous tier-3 report:
|
|
121
168
|
|
|
122
|
-
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"provider": "anthropic",
|
|
172
|
+
"apiKey": "sk-ant-...",
|
|
173
|
+
"depth": "tier-4",
|
|
174
|
+
"findings": [
|
|
175
|
+
{
|
|
176
|
+
"name": "SQL Injection",
|
|
177
|
+
"file": "src/db.js",
|
|
178
|
+
"line": 42,
|
|
179
|
+
"patch": "const stmt = db.prepare('SELECT * FROM users WHERE id = ?');\nstmt.run(id);"
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
```
|
|
123
184
|
|
|
124
|
-
|
|
125
|
-
|---|---|
|
|
126
|
-
| 400 | Path traversal attempt, oversized body (> 512 KB), or invalid JSON |
|
|
127
|
-
| 401 | Missing or invalid API key |
|
|
128
|
-
| 429 | Rate limit exceeded |
|
|
185
|
+
The job mode will be reported as `targeted-apply/tier-4(1)`. Only the listed findings are touched — no full re-scan.
|
|
129
186
|
|
|
130
187
|
---
|
|
131
188
|
|
|
132
189
|
### `POST /remediate`
|
|
133
190
|
|
|
134
|
-
Queue an AI-powered remediation job for a **provided findings list**. Returns immediately with a `jobId
|
|
191
|
+
Queue an AI-powered remediation job for a **provided findings list**. Returns immediately with a `jobId`.
|
|
135
192
|
|
|
136
|
-
Use `POST /audit`
|
|
193
|
+
Use `POST /audit/ai` for a fully agentic audit instead.
|
|
137
194
|
|
|
138
195
|
**Request**
|
|
139
196
|
```json
|
|
@@ -142,34 +199,28 @@ Use `POST /audit` instead if you want the server to run the scan itself.
|
|
|
142
199
|
"provider": "anthropic",
|
|
143
200
|
"apiKey": "sk-ant-...",
|
|
144
201
|
"model": "claude-opus-4-6",
|
|
145
|
-
"baseUrl": null
|
|
146
|
-
"severity": "HIGH"
|
|
202
|
+
"baseUrl": null
|
|
147
203
|
}
|
|
148
204
|
```
|
|
149
205
|
|
|
150
206
|
| Field | Required | Description |
|
|
151
207
|
|---|---|---|
|
|
152
|
-
| `findings` | yes | Array of finding objects
|
|
208
|
+
| `findings` | yes | Array of finding objects |
|
|
153
209
|
| `provider` | yes | `anthropic` \| `openai` \| `gemini` \| `ollama` |
|
|
154
210
|
| `apiKey` | yes | Provider API key |
|
|
155
|
-
| `model` | no | Defaults per provider
|
|
156
|
-
| `baseUrl` | no | Override base URL for
|
|
157
|
-
| `severity` | no | Minimum severity to fix. Default: `LOW` (fix all) |
|
|
211
|
+
| `model` | no | Defaults per provider |
|
|
212
|
+
| `baseUrl` | no | Override base URL for OpenAI-compatible services |
|
|
158
213
|
|
|
159
214
|
**Response — 202 Accepted**
|
|
160
215
|
```json
|
|
161
216
|
{ "jobId": "job_1_1711363200000" }
|
|
162
217
|
```
|
|
163
218
|
|
|
164
|
-
Job lifecycle: `pending → running → done | error`
|
|
165
|
-
|
|
166
219
|
---
|
|
167
220
|
|
|
168
221
|
### `POST /audit`
|
|
169
222
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
If no `provider`/`apiKey` are supplied, the server runs the scan only (no remediation) and the job transitions to `done` with just the `findings` array.
|
|
223
|
+
Static scan + AI remediation pipeline in one shot. Runs `quickScan` then passes findings to the remediator. If no `provider`/`apiKey` are supplied, runs the scan only.
|
|
173
224
|
|
|
174
225
|
**Request**
|
|
175
226
|
```json
|
|
@@ -185,7 +236,7 @@ If no `provider`/`apiKey` are supplied, the server runs the scan only (no remedi
|
|
|
185
236
|
|
|
186
237
|
| Field | Required | Description |
|
|
187
238
|
|---|---|---|
|
|
188
|
-
| `path` | no | Path to scan. Defaults to cwd.
|
|
239
|
+
| `path` | no | Path to scan. Defaults to cwd. |
|
|
189
240
|
| `provider` | no | If supplied with `apiKey`, AI remediation runs after the scan |
|
|
190
241
|
| `apiKey` | no | Provider API key |
|
|
191
242
|
| `model` | no | Defaults per provider |
|
|
@@ -196,69 +247,21 @@ If no `provider`/`apiKey` are supplied, the server runs the scan only (no remedi
|
|
|
196
247
|
|
|
197
248
|
```
|
|
198
249
|
HTTP/1.1 202 Accepted
|
|
199
|
-
Location: /jobs/
|
|
250
|
+
Location: /jobs/job_1_...
|
|
200
251
|
Retry-After: 2
|
|
201
252
|
```
|
|
202
|
-
```json
|
|
203
|
-
{ "jobId": "job_1_1711363200000" }
|
|
204
|
-
```
|
|
205
253
|
|
|
206
254
|
Job lifecycle: `pending → scanning → scanned → remediating → done | error`
|
|
207
255
|
|
|
208
|
-
Poll `GET /jobs/:id` or stream `GET /jobs/:id/stream` for progress.
|
|
209
|
-
|
|
210
|
-
**Job object during remediation**
|
|
211
|
-
```json
|
|
212
|
-
{
|
|
213
|
-
"id": "job_1_...",
|
|
214
|
-
"status": "remediating",
|
|
215
|
-
"total": 8,
|
|
216
|
-
"completed": 3,
|
|
217
|
-
"current": "SQL Injection"
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
**Job object when done**
|
|
222
|
-
```json
|
|
223
|
-
{
|
|
224
|
-
"id": "job_1_...",
|
|
225
|
-
"status": "done",
|
|
226
|
-
"createdAt": "...",
|
|
227
|
-
"startedAt": "...",
|
|
228
|
-
"completedAt": "...",
|
|
229
|
-
"findings": [ ... ],
|
|
230
|
-
"results": [
|
|
231
|
-
{
|
|
232
|
-
"finding": { ... },
|
|
233
|
-
"status": "remediated",
|
|
234
|
-
"exploitTest": { "filename": "__tests__/security/xss.test.js", "content": "..." },
|
|
235
|
-
"patch": { "filename": "src/app.js", "diff": "..." },
|
|
236
|
-
"refactorChecks": ["npm test", "npm run test:security"]
|
|
237
|
-
}
|
|
238
|
-
]
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
256
|
---
|
|
243
257
|
|
|
244
258
|
### `GET /jobs/:id`
|
|
245
259
|
|
|
246
|
-
Poll for job status. Works for jobs created by
|
|
260
|
+
Poll for job status. Works for jobs created by `POST /audit/ai`, `POST /remediate`, and `POST /audit`.
|
|
247
261
|
|
|
248
|
-
**Response — pending /
|
|
262
|
+
**Response — pending / running**
|
|
249
263
|
```json
|
|
250
|
-
{ "id": "job_1_...", "status": "
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
**Response — remediating (with progress)**
|
|
254
|
-
```json
|
|
255
|
-
{
|
|
256
|
-
"id": "job_1_...",
|
|
257
|
-
"status": "remediating",
|
|
258
|
-
"total": 8,
|
|
259
|
-
"completed": 3,
|
|
260
|
-
"current": "SQL Injection"
|
|
261
|
-
}
|
|
264
|
+
{ "id": "job_1_...", "status": "running", "depth": "tier-2", "createdAt": "..." }
|
|
262
265
|
```
|
|
263
266
|
|
|
264
267
|
**Response — done**
|
|
@@ -269,7 +272,7 @@ Poll for job status. Works for jobs created by both `POST /remediate` and `POST
|
|
|
269
272
|
"createdAt": "...",
|
|
270
273
|
"startedAt": "...",
|
|
271
274
|
"completedAt": "...",
|
|
272
|
-
"
|
|
275
|
+
"result": { ... }
|
|
273
276
|
}
|
|
274
277
|
```
|
|
275
278
|
|
|
@@ -293,18 +296,14 @@ curl -N http://localhost:3000/jobs/job_1_.../stream \
|
|
|
293
296
|
|
|
294
297
|
**Event format**
|
|
295
298
|
```
|
|
296
|
-
data: {"id":"job_1_...","status":"
|
|
297
|
-
|
|
298
|
-
data: {"id":"job_1_...","status":"scanned","findings":[...]}
|
|
299
|
-
|
|
300
|
-
data: {"id":"job_1_...","status":"remediating","total":8,"completed":1,"current":"SQL Injection"}
|
|
299
|
+
data: {"id":"job_1_...","status":"running","depth":"tier-2","log":"🔍 Exploring..."}
|
|
301
300
|
|
|
302
|
-
data: {"id":"job_1_...","status":"done","completedAt":"...","
|
|
301
|
+
data: {"id":"job_1_...","status":"done","completedAt":"...","result":{...}}
|
|
303
302
|
```
|
|
304
303
|
|
|
305
|
-
The connection
|
|
304
|
+
The connection closes automatically after the terminal state. Connecting to an already-completed job pushes the current state and closes immediately.
|
|
306
305
|
|
|
307
|
-
**Node.js example
|
|
306
|
+
**Node.js example**
|
|
308
307
|
```javascript
|
|
309
308
|
const es = new EventSource(
|
|
310
309
|
'http://localhost:3000/jobs/job_1_.../stream',
|
|
@@ -312,7 +311,7 @@ const es = new EventSource(
|
|
|
312
311
|
);
|
|
313
312
|
es.onmessage = (e) => {
|
|
314
313
|
const job = JSON.parse(e.data);
|
|
315
|
-
if (job.status === 'done') { console.log(job.
|
|
314
|
+
if (job.status === 'done') { console.log(job.result); es.close(); }
|
|
316
315
|
if (job.status === 'error') { console.error(job.error); es.close(); }
|
|
317
316
|
};
|
|
318
317
|
```
|
|
@@ -321,28 +320,19 @@ es.onmessage = (e) => {
|
|
|
321
320
|
|
|
322
321
|
## Full workflow examples
|
|
323
322
|
|
|
324
|
-
### curl —
|
|
323
|
+
### curl — tier-2 audit with polling
|
|
325
324
|
|
|
326
325
|
```bash
|
|
327
326
|
npx @lhi/tdd-audit serve --port 3000 --api-key mysecret &
|
|
328
327
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
-H "Content-Type: application/json" \
|
|
332
|
-
-d '{"path": "."}' | jq '.summary'
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### curl — full pipeline with polling
|
|
336
|
-
|
|
337
|
-
```bash
|
|
338
|
-
# Kick off audit
|
|
339
|
-
JOB=$(curl -s -X POST http://localhost:3000/audit \
|
|
328
|
+
# Start the audit
|
|
329
|
+
JOB=$(curl -s -X POST http://localhost:3000/audit/ai \
|
|
340
330
|
-H "Authorization: Bearer mysecret" \
|
|
341
331
|
-H "Content-Type: application/json" \
|
|
342
332
|
-d '{
|
|
343
|
-
"path": ".",
|
|
344
333
|
"provider": "anthropic",
|
|
345
|
-
"apiKey": "sk-ant-..."
|
|
334
|
+
"apiKey": "sk-ant-...",
|
|
335
|
+
"depth": "tier-2"
|
|
346
336
|
}' | jq -r '.jobId')
|
|
347
337
|
|
|
348
338
|
# Poll until done
|
|
@@ -351,30 +341,53 @@ while true; do
|
|
|
351
341
|
-H "Authorization: Bearer mysecret" | jq -r '.status')
|
|
352
342
|
echo "Status: $STATUS"
|
|
353
343
|
[ "$STATUS" = "done" ] || [ "$STATUS" = "error" ] && break
|
|
354
|
-
sleep
|
|
344
|
+
sleep 3
|
|
355
345
|
done
|
|
346
|
+
|
|
347
|
+
# Print findings summary
|
|
348
|
+
curl -s http://localhost:3000/jobs/$JOB \
|
|
349
|
+
-H "Authorization: Bearer mysecret" | jq '.result.summary'
|
|
356
350
|
```
|
|
357
351
|
|
|
358
|
-
### curl —
|
|
352
|
+
### curl — tier-3 report then targeted apply
|
|
359
353
|
|
|
360
354
|
```bash
|
|
361
|
-
|
|
355
|
+
# Step 1: get copy-ready patches (no writes)
|
|
356
|
+
JOB=$(curl -s -X POST http://localhost:3000/audit/ai \
|
|
362
357
|
-H "Authorization: Bearer mysecret" \
|
|
363
358
|
-H "Content-Type: application/json" \
|
|
364
|
-
-d '{"
|
|
359
|
+
-d '{"provider":"anthropic","apiKey":"sk-ant-...","depth":"tier-3"}' \
|
|
360
|
+
| jq -r '.jobId')
|
|
361
|
+
|
|
362
|
+
# (wait for done)
|
|
363
|
+
|
|
364
|
+
# Step 2: apply one specific patch
|
|
365
|
+
FINDING=$(curl -s http://localhost:3000/jobs/$JOB \
|
|
366
|
+
-H "Authorization: Bearer mysecret" \
|
|
367
|
+
| jq '.result.findings[0]')
|
|
368
|
+
|
|
369
|
+
curl -s -X POST http://localhost:3000/audit/ai \
|
|
370
|
+
-H "Authorization: Bearer mysecret" \
|
|
371
|
+
-H "Content-Type: application/json" \
|
|
372
|
+
-d "{
|
|
373
|
+
\"provider\": \"anthropic\",
|
|
374
|
+
\"apiKey\": \"sk-ant-...\",
|
|
375
|
+
\"depth\": \"tier-4\",
|
|
376
|
+
\"findings\": [$FINDING]
|
|
377
|
+
}" | jq '.jobId'
|
|
365
378
|
```
|
|
366
379
|
|
|
367
|
-
###
|
|
380
|
+
### curl — SARIF output for GitHub code scanning
|
|
368
381
|
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
382
|
+
```bash
|
|
383
|
+
JOB=$(curl -s -X POST http://localhost:3000/audit/ai \
|
|
384
|
+
-H "Authorization: Bearer mysecret" \
|
|
385
|
+
-H "Content-Type: application/json" \
|
|
386
|
+
-d '{"provider":"anthropic","apiKey":"sk-ant-...","depth":"tier-2","format":"sarif"}' \
|
|
387
|
+
| jq -r '.jobId')
|
|
388
|
+
|
|
389
|
+
# (wait for done)
|
|
390
|
+
|
|
391
|
+
curl -s http://localhost:3000/jobs/$JOB \
|
|
392
|
+
-H "Authorization: Bearer mysecret" | jq '.result' > results.sarif
|
|
380
393
|
```
|
package/docs/scanner.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Scanner Architecture
|
|
2
2
|
|
|
3
|
-
`lib/scanner.js`
|
|
3
|
+
`lib/scanner.js` provides the static vulnerability pattern engine used internally by the tdd-audit skill and the `POST /audit` pipeline. It is a pure Node.js module with no runtime dependencies — only `fs` and `path`.
|
|
4
|
+
|
|
5
|
+
> The scanner is an internal pre-processing component, not a standalone product. Customer-facing output is produced by the LLM audit (`--ai` / `POST /audit/ai`), which uses the scanner's signal as one input alongside its own tool-use exploration.
|
|
4
6
|
|
|
5
7
|
---
|
|
6
8
|
|
|
7
|
-
##
|
|
9
|
+
## Exports
|
|
8
10
|
|
|
9
11
|
| Export | Purpose |
|
|
10
12
|
|---|---|
|
|
@@ -64,7 +66,7 @@ Same skip rules, yields `.md` files only. Used by `scanPromptFiles`.
|
|
|
64
66
|
|
|
65
67
|
`.js` `.ts` `.jsx` `.tsx` `.mjs` `.py` `.go` `.dart` `.yml` `.yaml`
|
|
66
68
|
|
|
67
|
-
JSON and XML files are not walked by the code scanner. `package.json` is handled by `scanPackageJson()` and `.env*` files by `scanEnvFiles()` — both run as separate targeted checks. CI workflow files (`.yml`/`.yaml`) **are**
|
|
69
|
+
JSON and XML files are not walked by the code scanner. `package.json` is handled by `scanPackageJson()` and `.env*` files by `scanEnvFiles()` — both run as separate targeted checks. CI workflow files (`.yml`/`.yaml`) **are** scanned by `walkFiles()` for GitHub Actions expression injection and similar patterns.
|
|
68
70
|
|
|
69
71
|
---
|
|
70
72
|
|