price_manipulation_test
Test server-side price validation by sending manipulated price values like 0, 1, and -1 to identify vulnerabilities in e-commerce systems.
Instructions
Test client-side price manipulation by sending modified price values.
Sends price=0, price=1, price=-1, and negative quantity variants to check if the server validates prices server-side.
Returns: {"results": [{"test_case": str, "payload": str, "status": int, "length": int, "accepted": bool, "snippet": str}]}.
Side effects: May add items to cart or create orders at manipulated prices.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL that processes the purchase/cart action | |
| price_param | Yes | Parameter name for the price, e.g. 'price', 'amount', 'total' | |
| cart_endpoint | No | Separate cart/checkout endpoint to verify final price after manipulation | |
| extra_params | No | Additional form parameters, e.g. 'productId=1&quantity=1' | |
| auth_cookie | No | Session cookie for authenticated requests | |
| content_type | No | Request content type: 'form' or 'json' |
Implementation Reference
- src/tools/bizlogic.ts:13-204 (handler)The `price_manipulation_test` tool definition and handler implementation in `src/tools/bizlogic.ts`.
server.tool( "price_manipulation_test", "Test client-side price manipulation by sending modified price values.\n\nSends price=0, price=1, price=-1, and negative quantity variants to check if the server validates prices server-side.\n\nReturns: {\"results\": [{\"test_case\": str, \"payload\": str, \"status\": int, \"length\": int, \"accepted\": bool, \"snippet\": str}]}.\n\nSide effects: May add items to cart or create orders at manipulated prices.", { url: z .string() .describe("URL that processes the purchase/cart action"), price_param: z .string() .describe( "Parameter name for the price, e.g. 'price', 'amount', 'total'" ), cart_endpoint: z .string() .optional() .describe( "Separate cart/checkout endpoint to verify final price after manipulation" ), extra_params: z .string() .optional() .describe( "Additional form parameters, e.g. 'productId=1&quantity=1'" ), auth_cookie: z .string() .optional() .describe("Session cookie for authenticated requests"), content_type: z .string() .describe("Request content type: 'form' or 'json'") .optional(), }, async ({ url, price_param, cart_endpoint, extra_params, auth_cookie, content_type = "form", }) => { requireTool("curl"); const testCases: Array<[string, Record<string, string>]> = [ ["zero_price", { [price_param]: "0" }], ["one_cent", { [price_param]: "0.01" }], ["one_unit", { [price_param]: "1" }], ["negative_price", { [price_param]: "-100" }], ["large_negative", { [price_param]: "-99999" }], ["string_value", { [price_param]: "free" }], ]; // If there's a quantity parameter embedded in extra_params, also test negative quantity if (extra_params && extra_params.includes("quantity")) { testCases.push([ "negative_quantity", { [price_param]: "100", quantity: "-16" }, ]); } const results: Array<{ test_case: string; payload: Record<string, string>; status: number; length: number; accepted: boolean; response_snippet: string; }> = []; for (const [testName, params] of testCases) { let curlArgs: string[]; if (content_type === "json") { let baseParams: Record<string, string> = {}; if (extra_params) { // Parse extra_params as key=value pairs for (const pair of extra_params.split("&")) { if (pair.includes("=")) { const eqIdx = pair.indexOf("="); const k = pair.slice(0, eqIdx); const v = pair.slice(eqIdx + 1); baseParams[k] = v; } } } Object.assign(baseParams, params); const data = JSON.stringify(baseParams); curlArgs = [ "-sk", "-o", "-", "-w", "\n__META__%{http_code}:%{size_download}", "-X", "POST", "-H", "Content-Type: application/json", "-d", data, ]; } else { const formParts: string[] = []; if (extra_params) { formParts.push(extra_params); } for (const [k, v] of Object.entries(params)) { formParts.push(`${k}=${v}`); } const formData = formParts.join("&"); curlArgs = [ "-sk", "-o", "-", "-w", "\n__META__%{http_code}:%{size_download}", "-X", "POST", "-d", formData, ]; } if (auth_cookie) { curlArgs.push("-b", auth_cookie); } curlArgs.push(url); const res = await runCmd("curl", curlArgs); let body = res.stdout; const metaMarker = body.lastIndexOf("__META__"); let status = 0; let length = 0; if (metaMarker !== -1) { const meta = body.slice(metaMarker + 8).trim(); const parts = meta.split(":"); status = parts[0] ? parseInt(parts[0], 10) : 0; length = parts[1] ? parseInt(parts[1], 10) : 0; body = body.slice(0, metaMarker); } // Accepted if not an error status const accepted = [200, 201, 301, 302, 303].includes(status); results.push({ test_case: testName, payload: params, status, length, accepted, response_snippet: body.slice(0, 500), }); } // Optionally check the cart to see if manipulated prices stuck let cartResult: string | null = null; if (cart_endpoint) { const cartArgs = [ "-sk", "-o", "-", "-w", "\n__META__%{http_code}:%{size_download}", ]; if (auth_cookie) { cartArgs.push("-b", auth_cookie); } cartArgs.push(cart_endpoint); const cartRes = await runCmd("curl", cartArgs); let cartBody = cartRes.stdout; const metaMarker = cartBody.lastIndexOf("__META__"); if (metaMarker !== -1) { cartBody = cartBody.slice(0, metaMarker); } cartResult = cartBody.slice(0, 1000); } const acceptedCount = results.filter((r) => r.accepted).length; const result = { results, accepted_count: acceptedCount, cart_contents: cartResult, hint: acceptedCount > 0 ? `${acceptedCount} manipulated price(s) accepted. Check cart for final totals.` : "All manipulated prices rejected. Server-side validation appears intact.", }; return { content: [{ type: "text", text: JSON.stringify(result) }] }; } );