@fourteensystems/shipguard 0.2.6 → 0.2.7
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 +11 -2
- package/dist/engine/config.d.ts.map +1 -1
- package/dist/engine/config.js +2 -0
- package/dist/engine/config.js.map +1 -1
- package/dist/engine/report.d.ts.map +1 -1
- package/dist/engine/report.js +3 -0
- package/dist/engine/report.js.map +1 -1
- package/dist/engine/version.d.ts +1 -1
- package/dist/engine/version.js +1 -1
- package/dist/next/deps.js +1 -1
- package/dist/next/deps.js.map +1 -1
- package/dist/next/routes.d.ts.map +1 -1
- package/dist/next/routes.js +27 -3
- package/dist/next/routes.js.map +1 -1
- package/dist/next/routes.test.js +27 -0
- package/dist/next/routes.test.js.map +1 -1
- package/dist/next/wrappers.js +46 -3
- package/dist/next/wrappers.js.map +1 -1
- package/dist/rules/auth-boundary-missing.d.ts.map +1 -1
- package/dist/rules/auth-boundary-missing.js +71 -41
- package/dist/rules/auth-boundary-missing.js.map +1 -1
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js +11 -0
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/input-validation-missing.d.ts +5 -0
- package/dist/rules/input-validation-missing.d.ts.map +1 -0
- package/dist/rules/input-validation-missing.js +242 -0
- package/dist/rules/input-validation-missing.js.map +1 -0
- package/dist/rules/input-validation-missing.test.d.ts +2 -0
- package/dist/rules/input-validation-missing.test.d.ts.map +1 -0
- package/dist/rules/input-validation-missing.test.js +404 -0
- package/dist/rules/input-validation-missing.test.js.map +1 -0
- package/dist/rules/rate-limit-missing.d.ts.map +1 -1
- package/dist/rules/rate-limit-missing.js +46 -4
- package/dist/rules/rate-limit-missing.js.map +1 -1
- package/dist/rules/wrapper-unrecognized.d.ts.map +1 -1
- package/dist/rules/wrapper-unrecognized.js +6 -1
- package/dist/rules/wrapper-unrecognized.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { run, RULE_ID } from "./input-validation-missing.js";
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Helpers */
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
const DB_WRITE_SIGNALS = {
|
|
9
|
+
hasMutationEvidence: true,
|
|
10
|
+
hasDbWriteEvidence: true,
|
|
11
|
+
hasStripeWriteEvidence: false,
|
|
12
|
+
mutationDetails: ["prisma.create", "reads request body"],
|
|
13
|
+
};
|
|
14
|
+
const STRIPE_WRITE_SIGNALS = {
|
|
15
|
+
hasMutationEvidence: true,
|
|
16
|
+
hasDbWriteEvidence: false,
|
|
17
|
+
hasStripeWriteEvidence: true,
|
|
18
|
+
mutationDetails: ["stripe write operation", "reads request body"],
|
|
19
|
+
};
|
|
20
|
+
const BODY_ONLY_SIGNALS = {
|
|
21
|
+
hasMutationEvidence: true,
|
|
22
|
+
hasDbWriteEvidence: false,
|
|
23
|
+
hasStripeWriteEvidence: false,
|
|
24
|
+
mutationDetails: ["reads request body"],
|
|
25
|
+
};
|
|
26
|
+
function protectionSummary() {
|
|
27
|
+
return {
|
|
28
|
+
auth: { satisfied: false, enforced: false, sources: [], details: [], unverifiedWrappers: [] },
|
|
29
|
+
rateLimit: { satisfied: false, enforced: false, sources: [], details: [], unverifiedWrappers: [] },
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
let tmpDir;
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
tmpDir = path.join("/tmp", `shipguard-input-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
35
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
36
|
+
});
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
39
|
+
});
|
|
40
|
+
function createRoute(relPath, source, signals = DB_WRITE_SIGNALS) {
|
|
41
|
+
const fullPath = path.join(tmpDir, relPath);
|
|
42
|
+
mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
43
|
+
writeFileSync(fullPath, source);
|
|
44
|
+
const pathname = "/" + relPath
|
|
45
|
+
.replace(/\/route\.(ts|tsx|js|jsx)$/, "")
|
|
46
|
+
.replace(/^app\//, "");
|
|
47
|
+
return {
|
|
48
|
+
kind: "route-handler",
|
|
49
|
+
file: relPath,
|
|
50
|
+
isApi: pathname.startsWith("/api/"),
|
|
51
|
+
isPublic: true,
|
|
52
|
+
pathname,
|
|
53
|
+
signals,
|
|
54
|
+
protection: protectionSummary(),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function createAction(relPath, source, signals = DB_WRITE_SIGNALS) {
|
|
58
|
+
const fullPath = path.join(tmpDir, relPath);
|
|
59
|
+
mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
60
|
+
writeFileSync(fullPath, source);
|
|
61
|
+
return {
|
|
62
|
+
kind: "server-action",
|
|
63
|
+
file: relPath,
|
|
64
|
+
signals,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function makeIndex(routes = [], actions = []) {
|
|
68
|
+
return {
|
|
69
|
+
version: 1,
|
|
70
|
+
framework: "next-app-router",
|
|
71
|
+
rootDir: tmpDir,
|
|
72
|
+
deps: {
|
|
73
|
+
hasNextAuth: false, hasClerk: false, hasSupabase: false,
|
|
74
|
+
hasKinde: false, hasWorkOS: false, hasBetterAuth: false,
|
|
75
|
+
hasLucia: false, hasAuth0: false, hasIronSession: false,
|
|
76
|
+
hasFirebaseAuth: false, hasUpstashRatelimit: false, hasArcjet: false,
|
|
77
|
+
hasUnkey: false, hasPrisma: true, hasDrizzle: false, hasTrpc: false,
|
|
78
|
+
},
|
|
79
|
+
hints: {
|
|
80
|
+
auth: { functions: [], middlewareFiles: [], allowlistPaths: [] },
|
|
81
|
+
rateLimit: { wrappers: [], allowlistPaths: [] },
|
|
82
|
+
tenancy: { orgFieldNames: [] },
|
|
83
|
+
},
|
|
84
|
+
middleware: { authLikely: false, rateLimitLikely: false, matcherPatterns: [] },
|
|
85
|
+
wrappers: { wrappers: new Map() },
|
|
86
|
+
routes: { all: routes, mutationRoutes: routes },
|
|
87
|
+
serverActions: { all: actions, mutationActions: actions },
|
|
88
|
+
trpc: { detected: false, procedures: [], mutationProcedures: [] },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function makeConfig() {
|
|
92
|
+
return {
|
|
93
|
+
framework: "next-app-router",
|
|
94
|
+
include: ["app/**"],
|
|
95
|
+
exclude: [],
|
|
96
|
+
ci: { failOn: "critical", minConfidence: "high", minScore: 70, maxNewCritical: 0 },
|
|
97
|
+
scoring: { start: 100, penalties: { critical: 25, high: 10, med: 3, low: 1 } },
|
|
98
|
+
hints: {
|
|
99
|
+
auth: { functions: [], middlewareFiles: [], allowlistPaths: [] },
|
|
100
|
+
rateLimit: { wrappers: [], allowlistPaths: [] },
|
|
101
|
+
tenancy: { orgFieldNames: [] },
|
|
102
|
+
},
|
|
103
|
+
rules: { "INPUT-VALIDATION-MISSING": { severity: "high" } },
|
|
104
|
+
waiversFile: "shipguard.waivers.json",
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/* ------------------------------------------------------------------ */
|
|
108
|
+
/* Tests: should flag */
|
|
109
|
+
/* ------------------------------------------------------------------ */
|
|
110
|
+
describe("INPUT-VALIDATION-MISSING", () => {
|
|
111
|
+
describe("flags unvalidated input", () => {
|
|
112
|
+
it("request.json() + prisma.create without validation", () => {
|
|
113
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
114
|
+
export async function POST(request: Request) {
|
|
115
|
+
const body = await request.json();
|
|
116
|
+
await prisma.user.create({ data: body });
|
|
117
|
+
return Response.json({ ok: true });
|
|
118
|
+
}
|
|
119
|
+
`);
|
|
120
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
121
|
+
expect(findings).toHaveLength(1);
|
|
122
|
+
expect(findings[0].ruleId).toBe(RULE_ID);
|
|
123
|
+
expect(findings[0].confidence).toBe("high");
|
|
124
|
+
});
|
|
125
|
+
it("request.formData() + prisma.update without validation", () => {
|
|
126
|
+
const route = createRoute("app/api/profile/route.ts", `
|
|
127
|
+
export async function POST(request: Request) {
|
|
128
|
+
const data = await request.formData();
|
|
129
|
+
const name = data.get("name");
|
|
130
|
+
await prisma.user.update({ where: { id }, data: { name } });
|
|
131
|
+
return Response.json({ ok: true });
|
|
132
|
+
}
|
|
133
|
+
`);
|
|
134
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
135
|
+
expect(findings).toHaveLength(1);
|
|
136
|
+
expect(findings[0].ruleId).toBe(RULE_ID);
|
|
137
|
+
});
|
|
138
|
+
it("req.body + prisma.create without validation", () => {
|
|
139
|
+
const route = createRoute("app/api/items/route.ts", `
|
|
140
|
+
export async function POST(req: NextRequest) {
|
|
141
|
+
const data = req.body;
|
|
142
|
+
await prisma.item.create({ data });
|
|
143
|
+
return NextResponse.json({ ok: true });
|
|
144
|
+
}
|
|
145
|
+
`);
|
|
146
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
147
|
+
expect(findings).toHaveLength(1);
|
|
148
|
+
});
|
|
149
|
+
it("request.json() + Stripe write without validation", () => {
|
|
150
|
+
const route = createRoute("app/api/billing/route.ts", `
|
|
151
|
+
export async function POST(request: Request) {
|
|
152
|
+
const body = await request.json();
|
|
153
|
+
await stripe.subscriptions.create({ customer: body.customerId, items: [{ price: body.priceId }] });
|
|
154
|
+
return Response.json({ ok: true });
|
|
155
|
+
}
|
|
156
|
+
`, STRIPE_WRITE_SIGNALS);
|
|
157
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
158
|
+
expect(findings).toHaveLength(1);
|
|
159
|
+
});
|
|
160
|
+
it("server action with unvalidated input + DB write", () => {
|
|
161
|
+
const action = createAction("app/actions/create-post.ts", `
|
|
162
|
+
"use server";
|
|
163
|
+
export async function createPost(formData: FormData) {
|
|
164
|
+
const title = formData.get("title");
|
|
165
|
+
const body = await request.json();
|
|
166
|
+
await prisma.post.create({ data: { title } });
|
|
167
|
+
}
|
|
168
|
+
`);
|
|
169
|
+
const findings = run(makeIndex([], [action]), makeConfig());
|
|
170
|
+
expect(findings).toHaveLength(1);
|
|
171
|
+
expect(findings[0].message).toContain("Server action");
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
/* ------------------------------------------------------------------ */
|
|
175
|
+
/* Tests: should NOT flag (validation present) */
|
|
176
|
+
/* ------------------------------------------------------------------ */
|
|
177
|
+
describe("does NOT flag when validation present", () => {
|
|
178
|
+
it("zod z.object() + .parse()", () => {
|
|
179
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
180
|
+
import { z } from "zod";
|
|
181
|
+
const schema = z.object({ name: z.string(), email: z.string().email() });
|
|
182
|
+
export async function POST(request: Request) {
|
|
183
|
+
const body = await request.json();
|
|
184
|
+
const data = schema.parse(body);
|
|
185
|
+
await prisma.user.create({ data });
|
|
186
|
+
return Response.json({ ok: true });
|
|
187
|
+
}
|
|
188
|
+
`);
|
|
189
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
190
|
+
expect(findings).toHaveLength(0);
|
|
191
|
+
});
|
|
192
|
+
it("zod .safeParse()", () => {
|
|
193
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
194
|
+
import { z } from "zod";
|
|
195
|
+
const schema = z.object({ name: z.string() });
|
|
196
|
+
export async function POST(request: Request) {
|
|
197
|
+
const body = await request.json();
|
|
198
|
+
const result = schema.safeParse(body);
|
|
199
|
+
if (!result.success) return Response.json({ error: result.error }, { status: 400 });
|
|
200
|
+
await prisma.user.create({ data: result.data });
|
|
201
|
+
return Response.json({ ok: true });
|
|
202
|
+
}
|
|
203
|
+
`);
|
|
204
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
205
|
+
expect(findings).toHaveLength(0);
|
|
206
|
+
});
|
|
207
|
+
it("valibot v.parse()", () => {
|
|
208
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
209
|
+
import * as v from "valibot";
|
|
210
|
+
const schema = v.object({ name: v.string() });
|
|
211
|
+
export async function POST(request: Request) {
|
|
212
|
+
const body = await request.json();
|
|
213
|
+
const data = v.parse(schema, body);
|
|
214
|
+
await prisma.user.create({ data });
|
|
215
|
+
return Response.json({ ok: true });
|
|
216
|
+
}
|
|
217
|
+
`);
|
|
218
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
219
|
+
expect(findings).toHaveLength(0);
|
|
220
|
+
});
|
|
221
|
+
it("yup .validate()", () => {
|
|
222
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
223
|
+
import * as yup from "yup";
|
|
224
|
+
const schema = yup.object({ name: yup.string().required() });
|
|
225
|
+
export async function POST(request: Request) {
|
|
226
|
+
const body = await request.json();
|
|
227
|
+
const data = await schema.validate(body);
|
|
228
|
+
await prisma.user.create({ data });
|
|
229
|
+
return Response.json({ ok: true });
|
|
230
|
+
}
|
|
231
|
+
`);
|
|
232
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
233
|
+
expect(findings).toHaveLength(0);
|
|
234
|
+
});
|
|
235
|
+
it("next-safe-action createSafeActionClient", () => {
|
|
236
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
237
|
+
import { createSafeActionClient } from "next-safe-action";
|
|
238
|
+
const action = createSafeActionClient();
|
|
239
|
+
export async function POST(request: Request) {
|
|
240
|
+
const body = await request.json();
|
|
241
|
+
await prisma.user.create({ data: body });
|
|
242
|
+
}
|
|
243
|
+
`);
|
|
244
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
245
|
+
expect(findings).toHaveLength(0);
|
|
246
|
+
});
|
|
247
|
+
it("tRPC .input(z.object(...))", () => {
|
|
248
|
+
const route = createRoute("app/api/trpc/route.ts", `
|
|
249
|
+
import { z } from "zod";
|
|
250
|
+
const router = t.router({
|
|
251
|
+
create: t.procedure
|
|
252
|
+
.input(z.object({ name: z.string() }))
|
|
253
|
+
.mutation(async ({ input }) => {
|
|
254
|
+
const body = await request.json();
|
|
255
|
+
await prisma.user.create({ data: input });
|
|
256
|
+
}),
|
|
257
|
+
});
|
|
258
|
+
`);
|
|
259
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
260
|
+
expect(findings).toHaveLength(0);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
/* ------------------------------------------------------------------ */
|
|
264
|
+
/* Tests: JSON.parse is NOT schema validation */
|
|
265
|
+
/* ------------------------------------------------------------------ */
|
|
266
|
+
describe("JSON.parse does NOT suppress findings", () => {
|
|
267
|
+
it("JSON.parse is not schema validation", () => {
|
|
268
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
269
|
+
export async function POST(request: Request) {
|
|
270
|
+
const text = await request.json();
|
|
271
|
+
const config = JSON.parse(process.env.CONFIG);
|
|
272
|
+
await prisma.user.create({ data: text });
|
|
273
|
+
return Response.json({ ok: true });
|
|
274
|
+
}
|
|
275
|
+
`);
|
|
276
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
277
|
+
expect(findings).toHaveLength(1);
|
|
278
|
+
});
|
|
279
|
+
it("URL.parse is not schema validation", () => {
|
|
280
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
281
|
+
export async function POST(request: Request) {
|
|
282
|
+
const body = await request.json();
|
|
283
|
+
const parsed = URL.parse(body.url);
|
|
284
|
+
await prisma.user.create({ data: body });
|
|
285
|
+
return Response.json({ ok: true });
|
|
286
|
+
}
|
|
287
|
+
`);
|
|
288
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
289
|
+
expect(findings).toHaveLength(1);
|
|
290
|
+
});
|
|
291
|
+
it("schema.parse alongside JSON.parse still suppresses", () => {
|
|
292
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
293
|
+
import { z } from "zod";
|
|
294
|
+
const schema = z.object({ name: z.string() });
|
|
295
|
+
export async function POST(request: Request) {
|
|
296
|
+
const raw = await request.json();
|
|
297
|
+
const config = JSON.parse(process.env.CONFIG);
|
|
298
|
+
const data = schema.parse(raw);
|
|
299
|
+
await prisma.user.create({ data });
|
|
300
|
+
return Response.json({ ok: true });
|
|
301
|
+
}
|
|
302
|
+
`);
|
|
303
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
304
|
+
expect(findings).toHaveLength(0);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
/* ------------------------------------------------------------------ */
|
|
308
|
+
/* Edge cases */
|
|
309
|
+
/* ------------------------------------------------------------------ */
|
|
310
|
+
describe("edge cases", () => {
|
|
311
|
+
it("chained .parse() like getSchema().parse(body) suppresses finding", () => {
|
|
312
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
313
|
+
export async function POST(request: Request) {
|
|
314
|
+
const body = await request.json();
|
|
315
|
+
const data = getSchema("user").parse(body);
|
|
316
|
+
await prisma.user.create({ data });
|
|
317
|
+
return Response.json({ ok: true });
|
|
318
|
+
}
|
|
319
|
+
`);
|
|
320
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
321
|
+
expect(findings).toHaveLength(0);
|
|
322
|
+
});
|
|
323
|
+
it("commented-out schema.parse does NOT suppress finding", () => {
|
|
324
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
325
|
+
export async function POST(request: Request) {
|
|
326
|
+
const body = await request.json();
|
|
327
|
+
// TODO: add validation
|
|
328
|
+
// const data = schema.parse(body);
|
|
329
|
+
await prisma.user.create({ data: body });
|
|
330
|
+
return Response.json({ ok: true });
|
|
331
|
+
}
|
|
332
|
+
`);
|
|
333
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
334
|
+
expect(findings).toHaveLength(1);
|
|
335
|
+
});
|
|
336
|
+
it("block-commented schema.parse does NOT suppress finding", () => {
|
|
337
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
338
|
+
export async function POST(request: Request) {
|
|
339
|
+
const body = await request.json();
|
|
340
|
+
/*
|
|
341
|
+
const data = schema.parse(body);
|
|
342
|
+
*/
|
|
343
|
+
await prisma.user.create({ data: body });
|
|
344
|
+
return Response.json({ ok: true });
|
|
345
|
+
}
|
|
346
|
+
`);
|
|
347
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
348
|
+
expect(findings).toHaveLength(1);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
/* ------------------------------------------------------------------ */
|
|
352
|
+
/* Tests: should NOT flag (no write or no body read) */
|
|
353
|
+
/* ------------------------------------------------------------------ */
|
|
354
|
+
describe("does NOT flag when conditions incomplete", () => {
|
|
355
|
+
it("reads body but no DB/Stripe write", () => {
|
|
356
|
+
const route = createRoute("app/api/echo/route.ts", `
|
|
357
|
+
export async function POST(request: Request) {
|
|
358
|
+
const body = await request.json();
|
|
359
|
+
return Response.json(body);
|
|
360
|
+
}
|
|
361
|
+
`, BODY_ONLY_SIGNALS);
|
|
362
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
363
|
+
expect(findings).toHaveLength(0);
|
|
364
|
+
});
|
|
365
|
+
it("DB write but no body read", () => {
|
|
366
|
+
const route = createRoute("app/api/cron/route.ts", `
|
|
367
|
+
export async function POST() {
|
|
368
|
+
await prisma.job.create({ data: { ran: new Date() } });
|
|
369
|
+
return Response.json({ ok: true });
|
|
370
|
+
}
|
|
371
|
+
`);
|
|
372
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
373
|
+
expect(findings).toHaveLength(0);
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
/* ------------------------------------------------------------------ */
|
|
377
|
+
/* Confidence levels */
|
|
378
|
+
/* ------------------------------------------------------------------ */
|
|
379
|
+
describe("confidence levels", () => {
|
|
380
|
+
it("high confidence with DB write evidence", () => {
|
|
381
|
+
const route = createRoute("app/api/users/route.ts", `
|
|
382
|
+
export async function POST(request: Request) {
|
|
383
|
+
const body = await request.json();
|
|
384
|
+
await prisma.user.create({ data: body });
|
|
385
|
+
}
|
|
386
|
+
`);
|
|
387
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
388
|
+
expect(findings[0].confidence).toBe("high");
|
|
389
|
+
expect(findings[0].severity).toBe("high");
|
|
390
|
+
});
|
|
391
|
+
it("med confidence with Stripe write only (no DB)", () => {
|
|
392
|
+
const route = createRoute("app/api/billing/route.ts", `
|
|
393
|
+
export async function POST(request: Request) {
|
|
394
|
+
const body = await request.json();
|
|
395
|
+
await stripe.subscriptions.create({ items: body.items });
|
|
396
|
+
}
|
|
397
|
+
`, STRIPE_WRITE_SIGNALS);
|
|
398
|
+
const findings = run(makeIndex([route]), makeConfig());
|
|
399
|
+
expect(findings[0].confidence).toBe("med");
|
|
400
|
+
expect(findings[0].severity).toBe("med");
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
//# sourceMappingURL=input-validation-missing.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-validation-missing.test.js","sourceRoot":"","sources":["../../src/rules/input-validation-missing.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit-missing.d.ts","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAInE,eAAO,MAAM,OAAO,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"rate-limit-missing.d.ts","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAInE,eAAO,MAAM,OAAO,uBAAuB,CAAC;AAkD5C,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,EAAE,CAoGxE"}
|
|
@@ -22,6 +22,17 @@ const EXEMPT_PATH_PATTERNS = [
|
|
|
22
22
|
const WEBHOOK_PATH_PATTERNS = [
|
|
23
23
|
/webhook/i,
|
|
24
24
|
];
|
|
25
|
+
/**
|
|
26
|
+
* Login/signin paths — prime brute-force targets.
|
|
27
|
+
* Missing rate limiting on these is always critical.
|
|
28
|
+
*/
|
|
29
|
+
const LOGIN_PATH_PATTERNS = [
|
|
30
|
+
/\/login(\/|$)/i,
|
|
31
|
+
/\/signin(\/|$)/i,
|
|
32
|
+
/\/sign-in(\/|$)/i,
|
|
33
|
+
/\/auth\/login(\/|$)/i,
|
|
34
|
+
/\/auth\/signin(\/|$)/i,
|
|
35
|
+
];
|
|
25
36
|
/**
|
|
26
37
|
* Framework-managed routes where rate limiting is handled by the framework
|
|
27
38
|
* or is inappropriate (auth protocol flows, external callbacks, OG images).
|
|
@@ -56,10 +67,25 @@ export function run(index, config) {
|
|
|
56
67
|
const result = checkRoute(route, index, config);
|
|
57
68
|
if (result) {
|
|
58
69
|
const isAuthed = route.protection?.auth.satisfied ?? false;
|
|
70
|
+
// Severity bumps for high-value targets
|
|
71
|
+
let severity = result.severity;
|
|
72
|
+
let { confidence, confidenceRationale } = result;
|
|
73
|
+
if (isLoginPath(route.pathname)) {
|
|
74
|
+
severity = "critical";
|
|
75
|
+
confidence = "high";
|
|
76
|
+
confidenceRationale = "High: login/signin endpoint without rate limiting — prime brute-force target";
|
|
77
|
+
result.evidence.push("login/signin endpoint — brute-force risk");
|
|
78
|
+
}
|
|
79
|
+
else if (hasFormDataUpload(route, index) && !isAuthed) {
|
|
80
|
+
severity = "critical";
|
|
81
|
+
confidence = "high";
|
|
82
|
+
confidenceRationale = "High: public file upload endpoint without rate limiting — storage abuse risk";
|
|
83
|
+
result.evidence.push("public formData upload — storage abuse risk");
|
|
84
|
+
}
|
|
59
85
|
findings.push({
|
|
60
86
|
ruleId: RULE_ID,
|
|
61
|
-
severity: capSeverity(
|
|
62
|
-
confidence
|
|
87
|
+
severity: capSeverity(severity, maxSeverity),
|
|
88
|
+
confidence,
|
|
63
89
|
message: isAuthed
|
|
64
90
|
? `Authenticated API route has no recognized rate limiting`
|
|
65
91
|
: `Public API route has no recognized rate limiting`,
|
|
@@ -67,7 +93,7 @@ export function run(index, config) {
|
|
|
67
93
|
line: result.line,
|
|
68
94
|
snippet: result.snippet,
|
|
69
95
|
evidence: result.evidence,
|
|
70
|
-
confidenceRationale
|
|
96
|
+
confidenceRationale,
|
|
71
97
|
remediation: isAuthed
|
|
72
98
|
? [
|
|
73
99
|
"Consider adding rate limiting as defense-in-depth",
|
|
@@ -213,6 +239,9 @@ function hasRateLimitCall(src, wrappers) {
|
|
|
213
239
|
return true;
|
|
214
240
|
if (/@unkey\/ratelimit/.test(src))
|
|
215
241
|
return true;
|
|
242
|
+
// Upstash-style: ratelimit.limit(identifier) in route source
|
|
243
|
+
if (/(?:ratelimit|rateLimit|rl|limiter|rateLimiter)\.limit\s*\(/i.test(src))
|
|
244
|
+
return true;
|
|
216
245
|
return false;
|
|
217
246
|
}
|
|
218
247
|
/**
|
|
@@ -248,13 +277,26 @@ function isFrameworkManaged(pathname) {
|
|
|
248
277
|
return FRAMEWORK_MANAGED_PATTERNS.some((p) => p.test(pathname));
|
|
249
278
|
}
|
|
250
279
|
function hasBodyParsing(src) {
|
|
251
|
-
return /request\.json\s*\(|request\.formData\s*\(|req\.body/.test(src);
|
|
280
|
+
return /request\.json\s*\(|request\.formData\s*\(|request\.body\b|req\.body/.test(src);
|
|
252
281
|
}
|
|
253
282
|
function isExemptPath(pathname) {
|
|
254
283
|
if (!pathname)
|
|
255
284
|
return false;
|
|
256
285
|
return EXEMPT_PATH_PATTERNS.some((p) => p.test(pathname));
|
|
257
286
|
}
|
|
287
|
+
function isLoginPath(pathname) {
|
|
288
|
+
if (!pathname)
|
|
289
|
+
return false;
|
|
290
|
+
return LOGIN_PATH_PATTERNS.some((p) => p.test(pathname));
|
|
291
|
+
}
|
|
292
|
+
function hasFormDataUpload(route, index) {
|
|
293
|
+
const src = readSource(index.rootDir, route.file);
|
|
294
|
+
if (!src)
|
|
295
|
+
return false;
|
|
296
|
+
// FormData upload or raw body stream to blob/object storage
|
|
297
|
+
return /request\.formData\s*\(|req\.formData\s*\(/.test(src)
|
|
298
|
+
|| (/request\.body\b/.test(src) && /\bput\s*\(/.test(src));
|
|
299
|
+
}
|
|
258
300
|
function readSource(rootDir, file) {
|
|
259
301
|
try {
|
|
260
302
|
return readFileSync(path.join(rootDir, file), "utf8");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit-missing.js","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,CAAC,MAAM,OAAO,GAAG,oBAAoB,CAAC;AAE5C;;;GAGG;AACH,MAAM,oBAAoB,GAAG;IAC3B,WAAW;IACX,SAAS;IACT,UAAU;IACV,SAAS;IACT,WAAW;IACX,UAAU,EAAK,mCAAmC;IAClD,WAAW,EAAI,uCAAuC;CACvD,CAAC;AAEF;;;GAGG;AACH,MAAM,qBAAqB,GAAG;IAC5B,UAAU;CACX,CAAC;AAEF;;;GAGG;AACH,MAAM,0BAA0B,GAAG;IACjC,yBAAyB,EAAG,2DAA2D;IACvF,cAAc,EAAe,kEAAkE;IAC/F,aAAa,EAAgB,yBAAyB;IACtD,WAAW,EAAkB,wDAAwD;IACrF,UAAU,EAAmB,qBAAqB;IAClD,QAAQ,EAAqB,qDAAqD;IAClF,OAAO,EAAsB,mBAAmB;CACjD,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,KAAgB,EAAE,MAAuB;IAC3D,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,IAAI,UAAU,CAAC;IAElE,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QACrC,wBAAwB;QACxB,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,SAAS;QAE3B,+CAA+C;QAC/C,IAAI,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC;YAAE,SAAS;QAC3C,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC;YAAE,SAAS;QAE/E,2EAA2E;QAC3E,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,SAAS;YAAE,SAAS;QAEzE,8EAA8E;QAC9E,IAAI,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC;YAAE,SAAS;QAEjD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAChD,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;YAE3D,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"rate-limit-missing.js","sourceRoot":"","sources":["../../src/rules/rate-limit-missing.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper-unrecognized.d.ts","sourceRoot":"","sources":["../../src/rules/wrapper-unrecognized.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGnE,eAAO,MAAM,OAAO,yBAAyB,CAAC;AAU9C,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"wrapper-unrecognized.d.ts","sourceRoot":"","sources":["../../src/rules/wrapper-unrecognized.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGnE,eAAO,MAAM,OAAO,yBAAyB,CAAC;AAU9C,wBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,EAAE,CAoFxE"}
|
|
@@ -24,8 +24,9 @@ export function run(index, config) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
// Check if any wrapped routes are API routes (need rate limiting)
|
|
27
|
+
// Exclude routes that are already exempt from rate-limit (cron, webhook, etc.)
|
|
27
28
|
const apiFileSet = new Set(index.routes.all.filter((r) => r.isApi).map((r) => r.file));
|
|
28
|
-
const wrappedApiFiles = wrapper.usageFiles.filter((f) => apiFileSet.has(f));
|
|
29
|
+
const wrappedApiFiles = wrapper.usageFiles.filter((f) => apiFileSet.has(f) && !isRateLimitExemptPath(f));
|
|
29
30
|
if (wrappedApiFiles.length > 0) {
|
|
30
31
|
if (!wrapper.resolved || !wrapper.evidence.rateLimitEnforced) {
|
|
31
32
|
wouldTrigger.push("RATE-LIMIT-MISSING");
|
|
@@ -73,4 +74,8 @@ export function run(index, config) {
|
|
|
73
74
|
}
|
|
74
75
|
return findings;
|
|
75
76
|
}
|
|
77
|
+
/** Paths exempt from rate-limit — mirrors EXEMPT_PATH_PATTERNS + WEBHOOK patterns in rate-limit-missing. */
|
|
78
|
+
function isRateLimitExemptPath(file) {
|
|
79
|
+
return /\/cron\//.test(file) || /webhook/i.test(file) || /\/tasks\//.test(file);
|
|
80
|
+
}
|
|
76
81
|
//# sourceMappingURL=wrapper-unrecognized.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper-unrecognized.js","sourceRoot":"","sources":["../../src/rules/wrapper-unrecognized.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,OAAO,GAAG,sBAAsB,CAAC;AAE9C,MAAM,aAAa,GAA2B,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAEvF,SAAS,WAAW,CAAC,QAAkB,EAAE,GAAW;IAClD,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO,YAAY,GAAG,OAAO,CAAC,CAAC,CAAE,GAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,KAAgB,EAAE,MAAuB;IAC3D,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,IAAI,MAAM,CAAC;IAE9D,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACtD,2EAA2E;QAC3E,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,iBAAiB,EAAE,CAAC;YAC5F,SAAS;QACX,CAAC;QAED,mDAAmD;QACnD,MAAM,YAAY,GAAa,EAAE,CAAC;QAElC,8DAA8D;QAC9D,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChF,MAAM,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEtF,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;gBACxD,YAAY,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAED,kEAAkE;QAClE,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAC3D,CAAC;QACF,MAAM,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"wrapper-unrecognized.js","sourceRoot":"","sources":["../../src/rules/wrapper-unrecognized.ts"],"names":[],"mappings":"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"}
|