security.test_idor
Test for IDOR vulnerabilities by analyzing URLs with ID parameters to detect insecure direct object references in web applications.
Instructions
Test for IDOR (Insecure Direct Object Reference) vulnerabilities
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Target URL with ID parameter | |
| idParam | No | ID parameter name | id |
| testIds | No | IDs to test (e.g., [1, 2, 3]) |
Implementation Reference
- src/tools/security.ts:285-354 (handler)The handler function for 'security.test_idor' that tests for IDOR vulnerabilities by sending requests with different test IDs (default [1,2,3,999,1000]), compares responses to detect unauthorized access, saves findings if potential vuln detected, and returns formatted results.async ({ url, idParam = 'id', testIds = [1, 2, 3, 999, 1000] }: any): Promise<ToolResult> => { try { const results: any[] = []; let baselineResponse: AxiosResponse | null = null; for (const testId of testIds) { try { const response = await axios.get(url, { params: { [idParam]: testId }, validateStatus: () => true, timeout: 15000, }); if (!baselineResponse) { baselineResponse = response; } const isDifferent = response.status !== baselineResponse.status || response.data !== baselineResponse.data; const result = { id: testId, status: response.status, length: typeof response.data === 'string' ? response.data.length : JSON.stringify(response.data).length, isDifferent, accessible: response.status === 200, }; if (isDifferent && response.status === 200) { await saveFinding({ target: url, type: 'IDOR', severity: 'high', description: `Potential IDOR - different response for ID: ${testId}`, payload: `${idParam}=${testId}`, response: typeof response.data === 'string' ? response.data.substring(0, 1000) : JSON.stringify(response.data).substring(0, 1000), timestamp: new Date(), score: 7, }); } results.push(result); } catch (error: any) { results.push({ id: testId, error: error.message, }); } } const idorScore = results.some((r: any) => r.vulnerable) ? 8 : 4; await saveTestResult(url, 'idor_test', true, { results }, undefined, idorScore, JSON.stringify(testIds), JSON.stringify(results)); return formatToolResult(true, { results, summary: { totalTests: testIds.length, accessible: results.filter((r) => r.accessible).length, potentialVulns: results.filter((r) => r.isDifferent && r.accessible).length, }, }); } catch (error: any) { await saveTestResult(url, 'idor_test', false, null, error.message, 0, JSON.stringify(testIds), undefined); return formatToolResult(false, null, error.message); } }
- src/tools/security.ts:272-283 (schema)Input schema for the 'security.test_idor' tool defining parameters: url (required), idParam (default 'id'), testIds (array of numbers).type: 'object', properties: { url: { type: 'string', description: 'Target URL with ID parameter' }, idParam: { type: 'string', description: 'ID parameter name', default: 'id' }, testIds: { type: 'array', items: { type: 'number' }, description: 'IDs to test (e.g., [1, 2, 3])', }, }, required: ['url'], },
- src/tools/security.ts:268-355 (registration)Registration of the 'security.test_idor' tool using server.tool(), including description, inputSchema, and handler function reference.'security.test_idor', { description: 'Test for IDOR (Insecure Direct Object Reference) vulnerabilities', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'Target URL with ID parameter' }, idParam: { type: 'string', description: 'ID parameter name', default: 'id' }, testIds: { type: 'array', items: { type: 'number' }, description: 'IDs to test (e.g., [1, 2, 3])', }, }, required: ['url'], }, }, async ({ url, idParam = 'id', testIds = [1, 2, 3, 999, 1000] }: any): Promise<ToolResult> => { try { const results: any[] = []; let baselineResponse: AxiosResponse | null = null; for (const testId of testIds) { try { const response = await axios.get(url, { params: { [idParam]: testId }, validateStatus: () => true, timeout: 15000, }); if (!baselineResponse) { baselineResponse = response; } const isDifferent = response.status !== baselineResponse.status || response.data !== baselineResponse.data; const result = { id: testId, status: response.status, length: typeof response.data === 'string' ? response.data.length : JSON.stringify(response.data).length, isDifferent, accessible: response.status === 200, }; if (isDifferent && response.status === 200) { await saveFinding({ target: url, type: 'IDOR', severity: 'high', description: `Potential IDOR - different response for ID: ${testId}`, payload: `${idParam}=${testId}`, response: typeof response.data === 'string' ? response.data.substring(0, 1000) : JSON.stringify(response.data).substring(0, 1000), timestamp: new Date(), score: 7, }); } results.push(result); } catch (error: any) { results.push({ id: testId, error: error.message, }); } } const idorScore = results.some((r: any) => r.vulnerable) ? 8 : 4; await saveTestResult(url, 'idor_test', true, { results }, undefined, idorScore, JSON.stringify(testIds), JSON.stringify(results)); return formatToolResult(true, { results, summary: { totalTests: testIds.length, accessible: results.filter((r) => r.accessible).length, potentialVulns: results.filter((r) => r.isDifferent && r.accessible).length, }, }); } catch (error: any) { await saveTestResult(url, 'idor_test', false, null, error.message, 0, JSON.stringify(testIds), undefined); return formatToolResult(false, null, error.message); } } );