/**
 * API Security Tactics Module
 *
 * Detects API security vulnerabilities including IDOR, BOLA, GraphQL issues,
 * mass assignment, rate limiting, and excessive data exposure.
 * Priority 2 - critical for modern API-driven applications.
 *
 * @module agents/adversary/tactics/api
 */
import { registerTactic, generateFindingId, } from "./index.js";
// ============================================================================
// Patterns
// ============================================================================
const IDOR_PATTERNS = [
    {
        id: "idor-direct-id",
        name: "IDOR via Direct Object ID",
        description: "Direct use of user-provided ID without authorization check",
        cwe: "CWE-639",
        severity: "high",
        regex: /(?:findOne|findById|findByPk|get|query)\s*\([^)]*(?:req\.params|req\.query|params\.|query\.)(?:id|userId|postId|orderId)/gi,
    },
    {
        id: "idor-array-access",
        name: "IDOR via Array Index",
        description: "Array access with user-provided index without bounds/ownership check",
        cwe: "CWE-639",
        severity: "high",
        regex: /\[[^\]]*(?:req\.params|req\.query|params\.|query\.)\w+\](?![^;]*(?:owner|user|authorize|check|verify))/gi,
    },
    {
        id: "idor-file-path",
        name: "IDOR via File Path",
        description: "File access with user-provided path without validation",
        cwe: "CWE-639",
        severity: "critical",
        regex: /(?:readFile|createReadStream|unlink|rm)\s*\([^)]*(?:req\.params|req\.query|req\.body)/gi,
    },
    {
        id: "idor-sql-where",
        name: "IDOR in SQL WHERE Clause",
        description: "SQL query filtering by user-provided ID without authorization",
        cwe: "CWE-639",
        severity: "high",
        regex: /WHERE\s+\w+\s*=\s*(?:\$\{|%s|:)(?:id|userId|itemId)(?![^;]*(?:AND\s+(?:owner|user)|JOIN\s+\w+\s+ON))/gi,
    },
];
const BOLA_PATTERNS = [
    {
        id: "bola-missing-authz",
        name: "BOLA - Missing Object-Level Authorization",
        description: "Object retrieval without verifying ownership/permission",
        cwe: "CWE-284",
        severity: "high",
        regex: /(?:findOne|findById|get|retrieve)\s*\([^)]*\)(?:[^;]*\.then|[^{]*=>)(?![^}]{0,300}(?:owner|userId|belongsTo|canAccess|isAuthorized|authorize))/gis,
    },
    {
        id: "bola-update-no-check",
        name: "BOLA - Update Without Authorization",
        description: "Object update without ownership verification",
        cwe: "CWE-284",
        severity: "critical",
        regex: /(?:update|patch|put|set)\s*\([^)]*(?:req\.params|params\.)\w+[^)]*\)(?![^}]{0,200}(?:owner|userId|canUpdate|authorize))/gis,
    },
    {
        id: "bola-delete-no-check",
        name: "BOLA - Delete Without Authorization",
        description: "Object deletion without ownership verification",
        cwe: "CWE-284",
        severity: "critical",
        regex: /(?:delete|destroy|remove)\s*\([^)]*(?:req\.params|params\.)\w+[^)]*\)(?![^}]{0,200}(?:owner|userId|canDelete|authorize))/gis,
    },
    {
        id: "bola-bulk-operation",
        name: "BOLA - Bulk Operation Without Filtering",
        description: "Bulk operation without filtering by user ownership",
        cwe: "CWE-284",
        severity: "high",
        regex: /(?:updateMany|deleteMany|findMany)\s*\([^)]*\)(?![^}]{0,300}(?:where.*userId|filter.*owner))/gis,
    },
];
const GRAPHQL_PATTERNS = [
    {
        id: "graphql-no-depth-limit",
        name: "GraphQL Missing Depth Limit",
        description: "GraphQL endpoint without query depth limiting",
        cwe: "CWE-770",
        severity: "medium",
        regex: /GraphQLServer|ApolloServer|createServer\s*\(\s*\{(?![^}]*(?:depthLimit|validationRules|maxDepth))/gis,
    },
    {
        id: "graphql-no-cost-analysis",
        name: "GraphQL Missing Cost Analysis",
        description: "GraphQL without query cost analysis or complexity limiting",
        cwe: "CWE-770",
        severity: "medium",
        regex: /(?:GraphQLServer|ApolloServer)\s*\(\s*\{(?![^}]*(?:costAnalysis|queryComplexity|maxComplexity))/gis,
    },
    {
        id: "graphql-introspection-prod",
        name: "GraphQL Introspection Enabled",
        description: "GraphQL introspection enabled in production",
        cwe: "CWE-200",
        severity: "low",
        regex: /introspection\s*:\s*true|(?:GraphQLServer|ApolloServer)(?![^}]*introspection\s*:\s*false)/gi,
    },
    {
        id: "graphql-batch-attack",
        name: "GraphQL Batch Query Vulnerability",
        description: "GraphQL allows unbounded batch queries",
        cwe: "CWE-770",
        severity: "medium",
        regex: /(?:GraphQLServer|ApolloServer)(?![^}]*(?:batchLimit|maxBatchSize|queryBatching\s*:\s*false))/gi,
    },
];
const MASS_ASSIGNMENT_PATTERNS = [
    {
        id: "mass-assignment-spread",
        name: "Mass Assignment via Object Spread",
        description: "Object spread operator with unsanitized user input",
        cwe: "CWE-915",
        severity: "high",
        regex: /(?:create|update|set)\s*\(\s*\{\s*\.\.\.(?:req\.body|body|input|data)\s*\}/gi,
    },
    {
        id: "mass-assignment-assign",
        name: "Mass Assignment via Object.assign",
        description: "Object.assign with unfiltered user input",
        cwe: "CWE-915",
        severity: "high",
        regex: /Object\.assign\s*\([^,]*,\s*(?:req\.body|body|input|data)\s*\)/gi,
    },
    {
        id: "mass-assignment-orm",
        name: "Mass Assignment in ORM",
        description: "ORM accepting all user input without field filtering",
        cwe: "CWE-915",
        severity: "high",
        regex: /(?:User|Model|Entity)\.(?:create|update)\s*\(\s*(?:req\.body|body|input)(?!\s*,\s*\{[^}]*(?:fields|attributes|only|pick)\s*:)/gi,
    },
    {
        id: "mass-assignment-python",
        name: "Mass Assignment in Python ORM",
        description: "Django/SQLAlchemy accepting unfiltered input",
        cwe: "CWE-915",
        severity: "high",
        regex: /(?:Model|objects)\.(?:create|update)\s*\(\s*\*\*(?:request\.data|data|input)\s*\)/gi,
    },
];
const RATE_LIMIT_PATTERNS = [
    {
        id: "api-no-rate-limit",
        name: "API Endpoint Without Rate Limiting",
        description: "Public API endpoint without rate limiting middleware",
        cwe: "CWE-770",
        severity: "medium",
        regex: /(?:app|router)\.(?:get|post|put|delete|patch)\s*\(\s*['"][^'"]+['"](?![^}]{0,500}(?:rateLimit|throttle|limiter|slowDown))/gis,
    },
    {
        id: "api-expensive-no-limit",
        name: "Expensive Operation Without Rate Limit",
        description: "Resource-intensive operation without throttling",
        cwe: "CWE-770",
        severity: "high",
        regex: /(?:export|generate|process|compute|calculate|search)\s*[:=]\s*async[^{]*\{(?![^}]{0,800}(?:rateLimit|throttle|queue|defer))/gis,
    },
    {
        id: "api-file-upload-no-limit",
        name: "File Upload Without Rate Limiting",
        description: "File upload endpoint without rate limiting or size limits",
        cwe: "CWE-770",
        severity: "high",
        regex: /(?:upload|multer|formidable)(?![^}]{0,500}(?:limits|maxFileSize|rateLimit))/gi,
    },
];
const DATA_EXPOSURE_PATTERNS = [
    {
        id: "api-full-object-return",
        name: "Excessive Data Exposure - Full Object Return",
        description: "Returning entire object including sensitive fields",
        cwe: "CWE-200",
        severity: "medium",
        regex: /res\.(?:json|send)\s*\(\s*(?:user|account|profile|model)(?!\.[^)]*(?:toPublic|sanitize|pick|omit|select))\s*\)/gi,
    },
    {
        id: "api-all-fields-select",
        name: "Excessive Data Exposure - SELECT *",
        description: "Database query selecting all fields instead of specific ones",
        cwe: "CWE-200",
        severity: "low",
        regex: /SELECT\s+\*\s+FROM|find(?:All|Many)\s*\(\s*(?:\{|$)(?![^}]*(?:select|attributes|fields))/gi,
    },
    {
        id: "api-internal-details",
        name: "Excessive Data Exposure - Internal Details",
        description: "API response includes internal implementation details",
        cwe: "CWE-200",
        severity: "low",
        regex: /res\.(?:json|send)\s*\([^)]*(?:stack|error\.stack|__v|_id|internal|debug)/gi,
    },
    {
        id: "api-sensitive-fields",
        name: "Excessive Data Exposure - Sensitive Fields",
        description: "Response includes password, token, or other sensitive fields",
        cwe: "CWE-200",
        severity: "high",
        regex: /res\.(?:json|send)\s*\([^)]*\{[^}]*(?:password|token|secret|apiKey|privateKey)/gi,
    },
];
// ============================================================================
// Tactic Implementation
// ============================================================================
const apiTactic = {
    focusArea: "api",
    name: "API Security",
    description: "Detects API vulnerabilities including IDOR, BOLA, GraphQL issues, mass assignment, and data exposure",
    patterns: [
        ...IDOR_PATTERNS,
        ...BOLA_PATTERNS,
        ...GRAPHQL_PATTERNS,
        ...MASS_ASSIGNMENT_PATTERNS,
        ...RATE_LIMIT_PATTERNS,
        ...DATA_EXPOSURE_PATTERNS,
    ],
    async analyzeFile(file, config) {
        const findings = [];
        for (const pattern of this.patterns) {
            if (!pattern.regex)
                continue;
            // Reset regex state
            pattern.regex.lastIndex = 0;
            let match;
            while ((match = pattern.regex.exec(file.content)) !== null) {
                // Calculate line number
                const beforeMatch = file.content.substring(0, match.index);
                const lineNum = (beforeMatch.match(/\n/g) || []).length + 1;
                // Skip if in comment
                const line = file.lines[lineNum - 1] || "";
                if (isInComment(line)) {
                    continue;
                }
                // Skip known false positives
                if (isFalsePositive(match[0], pattern.id, file)) {
                    continue;
                }
                const finding = {
                    id: generateFindingId("api", file.relativePath, lineNum, pattern.id),
                    tacticName: "api",
                    focusArea: "api",
                    patternId: pattern.id,
                    file: file.relativePath,
                    line: lineNum,
                    message: `${pattern.name}: ${pattern.description}`,
                    severity: pattern.severity,
                    confidence: calculateConfidence(match[0], pattern, file),
                    evidence: match[0].substring(0, 200),
                    cweIds: [pattern.cwe],
                    mitreIds: getMitreIds(pattern.id),
                    suggestedFix: getSuggestedFix(pattern.id),
                };
                findings.push(finding);
            }
        }
        return findings;
    },
    async generatePoC(finding) {
        const pocMap = {
            "idor-direct-id": () => idorPoC(finding),
            "idor-file-path": () => idorFilePoC(finding),
            "bola-missing-authz": () => bolaPoC(finding),
            "bola-update-no-check": () => bolaUpdatePoC(finding),
            "bola-delete-no-check": () => bolaDeletePoC(finding),
            "graphql-no-depth-limit": () => graphqlDepthPoC(finding),
            "graphql-batch-attack": () => graphqlBatchPoC(finding),
            "mass-assignment-spread": () => massAssignmentPoC(finding),
            "mass-assignment-orm": () => massAssignmentPoC(finding),
            "api-no-rate-limit": () => rateLimitPoC(finding),
            "api-full-object-return": () => dataExposurePoC(finding),
        };
        const generator = pocMap[finding.patternId];
        return generator ? generator() : null;
    },
    getPromptEnhancement() {
        return `When analyzing for API security vulnerabilities, focus on:

1. **IDOR (Insecure Direct Object References)**:
   - User-provided IDs used directly in database queries
   - No verification that user owns/can access the resource
   - Array/file access with user-controlled indices/paths
   - Check for authorization logic after object retrieval

2. **BOLA (Broken Object Level Authorization)**:
   - Create, Read, Update, Delete operations on objects
   - Verify ownership/permission checks exist before operations
   - Look for missing \`userId\`, \`owner\`, \`canAccess\` checks
   - Check bulk operations filter by user

3. **GraphQL Security**:
   - Query depth limiting to prevent nested query attacks
   - Query complexity/cost analysis
   - Batch query limits
   - Introspection disabled in production
   - Field-level authorization

4. **Mass Assignment**:
   - Object spread (\`{ ...req.body }\`) without field filtering
   - \`Object.assign()\` with unvalidated input
   - ORM \`.create()\` or \`.update()\` accepting raw input
   - Look for \`pick\`, \`omit\`, \`fields\`, \`attributes\` filtering

5. **Rate Limiting**:
   - Public API endpoints without rate limiting middleware
   - Expensive operations (export, search, file upload)
   - Authentication endpoints separately limited
   - Different limits for authenticated vs unauthenticated

6. **Excessive Data Exposure**:
   - Returning full model objects instead of DTOs
   - \`SELECT *\` instead of specific fields
   - Sensitive fields (password, tokens, internal IDs) in responses
   - Error messages revealing stack traces or internal details

For each vulnerability, trace:
- Where does user input enter the system?
- What authorization checks exist (if any)?
- Can an attacker access/modify resources they don't own?
- What data is returned to the client?`;
    },
    getRelevantFilePatterns() {
        return [
            "**/api/**",
            "**/routes/**",
            "**/handlers/**",
            "**/controllers/**",
            "**/resolvers/**",
            "**/graphql/**",
            "**/rest/**",
            "**/*route*",
            "**/*handler*",
            "**/*controller*",
            "**/*resolver*",
            "**/*endpoint*",
        ];
    },
};
// ============================================================================
// Helper Functions
// ============================================================================
function isInComment(line) {
    const trimmed = line.trim();
    return trimmed.startsWith("//") || trimmed.startsWith("*") || trimmed.startsWith("#");
}
function isFalsePositive(match, patternId, file) {
    // Skip test files for most patterns
    if (file.relativePath.includes("test") ||
        file.relativePath.includes("spec") ||
        file.relativePath.includes("mock") ||
        file.relativePath.includes("fixture")) {
        return true;
    }
    // Skip example/demo files
    if (file.relativePath.includes("example") ||
        file.relativePath.includes("demo") ||
        file.relativePath.includes("sample")) {
        return true;
    }
    // Skip if authorization check is nearby (within the match)
    const authKeywords = /(?:authorize|canAccess|isOwner|checkPermission|hasPermission|verifyOwnership|belongsTo)/i;
    if (authKeywords.test(match)) {
        return true;
    }
    return false;
}
function calculateConfidence(match, pattern, file) {
    let confidence = 70;
    // Higher confidence for production-looking code
    if (!file.relativePath.includes("test") && !file.relativePath.includes("example")) {
        confidence += 10;
    }
    // Higher confidence for critical patterns
    if (pattern.severity === "critical") {
        confidence += 10;
    }
    // Lower confidence if there are authorization-related imports nearby
    if (file.content.includes("authorize") || file.content.includes("permission")) {
        confidence -= 10;
    }
    // Higher confidence for obvious unsafe patterns
    if (match.includes("req.params") || match.includes("req.query")) {
        confidence += 5;
    }
    return Math.min(95, Math.max(50, confidence));
}
function getMitreIds(patternId) {
    const mapping = {
        "idor-direct-id": ["T1078", "T1213"],
        "idor-file-path": ["T1083", "T1005"],
        "bola-missing-authz": ["T1078", "T1213"],
        "bola-update-no-check": ["T1565", "T1078"],
        "bola-delete-no-check": ["T1485", "T1078"],
        "graphql-no-depth-limit": ["T1499"],
        "graphql-batch-attack": ["T1499"],
        "mass-assignment-spread": ["T1068", "T1078"],
        "mass-assignment-orm": ["T1068", "T1078"],
        "api-no-rate-limit": ["T1499", "T1110"],
        "api-expensive-no-limit": ["T1499"],
        "api-full-object-return": ["T1530", "T1213"],
        "api-sensitive-fields": ["T1552", "T1213"],
    };
    return mapping[patternId] || ["T1190"];
}
function getSuggestedFix(patternId) {
    const fixes = {
        "idor-direct-id": "Add authorization check: verify user owns/can access the resource before retrieval",
        "idor-file-path": "Validate file path against allowed list, check ownership, use indirect references",
        "idor-array-access": "Validate array index, check ownership of accessed resource",
        "bola-missing-authz": "Add ownership check: WHERE user_id = current_user_id or use canAccess() method",
        "bola-update-no-check": "Verify user owns resource before update: if (resource.userId !== req.user.id) throw Forbidden",
        "bola-delete-no-check": "Verify user owns resource before delete: check ownership in WHERE clause",
        "bola-bulk-operation": "Filter bulk operations by user: { where: { userId: req.user.id } }",
        "graphql-no-depth-limit": "Add depth limiting: validationRules: [depthLimit(7)]",
        "graphql-no-cost-analysis": "Add query complexity analysis: validationRules: [costAnalysis({ maximumCost: 1000 })]",
        "graphql-introspection-prod": "Disable introspection in production: introspection: process.env.NODE_ENV !== 'production'",
        "graphql-batch-attack": "Limit batch queries: batchLimit: 5 or queryBatching: false",
        "mass-assignment-spread": "Use field filtering: const { allowedField1, allowedField2 } = req.body",
        "mass-assignment-assign": "Use pick/omit: Object.assign(model, _.pick(req.body, ['safe', 'fields']))",
        "mass-assignment-orm": "Specify allowed fields: Model.create(data, { fields: ['name', 'email'] })",
        "api-no-rate-limit": "Add rate limiting middleware: app.use('/api', rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }))",
        "api-expensive-no-limit": "Add throttling: use queue/defer for expensive operations, add rate limits",
        "api-file-upload-no-limit": "Add limits: multer({ limits: { fileSize: 5 * 1024 * 1024 } }), add rate limiting",
        "api-full-object-return": "Return DTO instead: res.json(user.toPublicJSON()) or use serializer",
        "api-all-fields-select": "Select specific fields: Model.findOne({ attributes: ['id', 'name', 'email'] })",
        "api-internal-details": "Remove internal details from responses, use custom error handler",
        "api-sensitive-fields": "Exclude sensitive fields: use toJSON method, serializer, or explicit field selection",
    };
    return fixes[patternId] || "Review authorization and data exposure in API endpoint";
}
// ============================================================================
// PoC Generators
// ============================================================================
function idorPoC(finding) {
    const steps = [
        {
            order: 1,
            action: "identify-endpoint",
            description: "Identify the API endpoint accepting resource ID",
            command: `Review ${finding.file}:${finding.line}`,
            expectedResult: "Endpoint identified (e.g., GET /api/users/:id)",
        },
        {
            order: 2,
            action: "access-own-resource",
            description: "Access your own resource to understand response format",
            command: `curl -H "Authorization: Bearer USER_A_TOKEN" https://target/api/resource/123`,
            expectedResult: "Own resource data returned successfully",
        },
        {
            order: 3,
            action: "enumerate-ids",
            description: "Try accessing sequential IDs or discovered IDs",
            command: `curl -H "Authorization: Bearer USER_A_TOKEN" https://target/api/resource/124`,
            expectedResult: "Other user's resource data returned without authorization check",
        },
        {
            order: 4,
            action: "confirm-idor",
            description: "Confirm access to resources belonging to other users",
            command: `for id in {1..100}; do curl -H "Authorization: Bearer USER_A_TOKEN" https://target/api/resource/$id; done`,
            expectedResult: "Can read resources owned by other users",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Valid user account and authentication token",
            "Knowledge of resource ID format",
        ],
        steps,
        payload: "GET /api/resource/{other_user_id}",
        expectedResult: "Unauthorized access to other users' resources",
        safeTestInstructions: "Test with multiple test accounts you control. Never access real user data. Test on staging/development environment only.",
    };
}
function idorFilePoC(finding) {
    const steps = [
        {
            order: 1,
            action: "identify-endpoint",
            description: "Identify file download/access endpoint",
            command: `Review ${finding.file}:${finding.line}`,
            expectedResult: "File endpoint identified",
        },
        {
            order: 2,
            action: "test-path-traversal",
            description: "Test for path traversal vulnerability",
            command: `curl -H "Authorization: Bearer TOKEN" https://target/api/file?path=../../../etc/passwd`,
            expectedResult: "System file or other user's file accessible",
        },
        {
            order: 3,
            action: "enumerate-files",
            description: "Enumerate accessible files",
            command: `curl -H "Authorization: Bearer TOKEN" https://target/api/file?path=../uploads/user_123/document.pdf`,
            expectedResult: "Access to files belonging to other users",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Valid user account",
            "Understanding of file storage structure",
        ],
        steps,
        payload: "?path=../../../../etc/passwd",
        expectedResult: "Unauthorized file access via path manipulation",
        safeTestInstructions: "Test on isolated environment. Try accessing only test files you created. Never access system files or real user data.",
    };
}
function bolaPoC(finding) {
    const steps = [
        {
            order: 1,
            action: "create-resources",
            description: "Create test resources with two different user accounts",
            command: "Create resource A with User A, resource B with User B",
            expectedResult: "Both resources created with known IDs",
        },
        {
            order: 2,
            action: "test-cross-access",
            description: "Try to access User B's resource using User A's token",
            command: `curl -H "Authorization: Bearer USER_A_TOKEN" https://target/api/resource/{USER_B_RESOURCE_ID}`,
            expectedResult: "User B's resource returned without authorization check",
        },
        {
            order: 3,
            action: "verify-bola",
            description: "Verify authorization is not enforced at object level",
            command: "Confirm authentication is checked but not object-level authorization",
            expectedResult: "Authenticated users can access any resource regardless of ownership",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Two test user accounts",
            "Ability to create resources",
        ],
        steps,
        payload: "GET /api/resource/{other_user_resource_id}",
        expectedResult: "Access to resources without ownership verification",
        safeTestInstructions: "Use only test accounts you control. Test on development/staging environment. Do not access real user resources.",
    };
}
function bolaUpdatePoC(finding) {
    const steps = [
        {
            order: 1,
            action: "identify-update-endpoint",
            description: "Identify the update endpoint",
            command: `Review ${finding.file}:${finding.line}`,
            expectedResult: "Update endpoint identified (e.g., PUT /api/resource/:id)",
        },
        {
            order: 2,
            action: "create-target-resource",
            description: "Create a resource with User B",
            command: `curl -X POST -H "Authorization: Bearer USER_B_TOKEN" https://target/api/resource -d '{"name":"Original"}'`,
            expectedResult: "Resource created with known ID",
        },
        {
            order: 3,
            action: "modify-other-resource",
            description: "Attempt to modify User B's resource using User A's token",
            command: `curl -X PUT -H "Authorization: Bearer USER_A_TOKEN" https://target/api/resource/{USER_B_ID} -d '{"name":"Modified"}'`,
            expectedResult: "Resource modified without ownership check",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Two test accounts",
            "Ability to create and modify resources",
        ],
        steps,
        payload: `PUT /api/resource/{other_user_id} {"name":"Attacker Modified"}`,
        expectedResult: "Unauthorized modification of other users' resources",
        safeTestInstructions: "Test with controlled test accounts only. Never modify real user data. Test on isolated environment.",
    };
}
function bolaDeletePoC(finding) {
    const steps = [
        {
            order: 1,
            action: "identify-delete-endpoint",
            description: "Identify the delete endpoint",
            command: `Review ${finding.file}:${finding.line}`,
            expectedResult: "Delete endpoint identified",
        },
        {
            order: 2,
            action: "create-target-resource",
            description: "Create a test resource with User B",
            command: `curl -X POST -H "Authorization: Bearer USER_B_TOKEN" https://target/api/resource -d '{"name":"Test"}'`,
            expectedResult: "Resource created",
        },
        {
            order: 3,
            action: "delete-other-resource",
            description: "Attempt to delete User B's resource using User A's token",
            command: `curl -X DELETE -H "Authorization: Bearer USER_A_TOKEN" https://target/api/resource/{USER_B_ID}`,
            expectedResult: "Resource deleted without ownership verification",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Two test accounts",
            "Ability to create resources",
        ],
        steps,
        payload: "DELETE /api/resource/{other_user_id}",
        expectedResult: "Unauthorized deletion of other users' resources",
        safeTestInstructions: "Test with disposable test data only. Never delete real user resources. Use isolated test environment.",
    };
}
function graphqlDepthPoC(finding) {
    const steps = [
        {
            order: 1,
            action: "craft-deep-query",
            description: "Craft a deeply nested GraphQL query",
            command: `Create query with 20+ levels of nesting`,
            expectedResult: "Deeply nested query prepared",
        },
        {
            order: 2,
            action: "execute-query",
            description: "Execute the deeply nested query",
            command: `curl -X POST https://target/graphql -d '{"query":"query { user { posts { comments { author { posts { comments { ... } } } } } } }"}'`,
            expectedResult: "Query executes, potentially causing performance degradation",
        },
        {
            order: 3,
            action: "measure-impact",
            description: "Measure server response time and resource usage",
            command: "Monitor query execution time and server CPU/memory",
            expectedResult: "Significant resource consumption, potential DoS",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Access to GraphQL endpoint",
            "Understanding of GraphQL schema",
        ],
        steps,
        payload: "query { user { posts { comments { author { posts { comments { author { ... nested 20 levels } } } } } } }",
        expectedResult: "Server resource exhaustion via deeply nested query",
        safeTestInstructions: "Test on staging environment only. Start with moderate nesting (5-7 levels). Monitor server resources. Never DoS production.",
    };
}
function graphqlBatchPoC(finding) {
    const steps = [
        {
            order: 1,
            action: "craft-batch",
            description: "Craft a batch query with many operations",
            command: "Create query array with 100+ identical expensive queries",
            expectedResult: "Batch query prepared",
        },
        {
            order: 2,
            action: "execute-batch",
            description: "Execute the batch query",
            command: `curl -X POST https://target/graphql -d '[{"query":"query{users{...}}"},{"query":"query{users{...}}"},...x100]'`,
            expectedResult: "All queries execute, multiplying resource consumption",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "GraphQL endpoint allowing batched queries",
        ],
        steps,
        payload: "[{\"query\":\"expensive_query\"}] repeated 100+ times",
        expectedResult: "Server DoS via batch query amplification",
        safeTestInstructions: "Test on isolated environment. Start with small batches (5-10). Never DoS production systems.",
    };
}
function massAssignmentPoC(finding) {
    const steps = [
        {
            order: 1,
            action: "identify-model-fields",
            description: "Identify model fields including privileged ones",
            command: `Review ${finding.file} and model definition`,
            expectedResult: "Fields like 'isAdmin', 'role', 'credits' identified",
        },
        {
            order: 2,
            action: "test-normal-update",
            description: "Test normal profile update",
            command: `curl -X PUT -H "Authorization: Bearer TOKEN" https://target/api/profile -d '{"name":"Test"}'`,
            expectedResult: "Normal field updated successfully",
        },
        {
            order: 3,
            action: "inject-privileged-field",
            description: "Inject privileged field in request",
            command: `curl -X PUT -H "Authorization: Bearer TOKEN" https://target/api/profile -d '{"name":"Test","isAdmin":true,"role":"admin"}'`,
            expectedResult: "Privileged field accepted and user escalated to admin",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Valid user account",
            "Knowledge of model schema",
            "Update endpoint accepting JSON body",
        ],
        steps,
        payload: `{"name":"Test","isAdmin":true,"role":"admin","credits":999999}`,
        expectedResult: "Privilege escalation or unauthorized field modification via mass assignment",
        safeTestInstructions: "Test with test account only. Verify after test and revert any privilege changes. Test on development environment.",
    };
}
function rateLimitPoC(finding) {
    const steps = [
        {
            order: 1,
            action: "identify-endpoint",
            description: "Identify endpoint without rate limiting",
            command: `Review ${finding.file}:${finding.line}`,
            expectedResult: "Endpoint identified",
        },
        {
            order: 2,
            action: "test-rapid-requests",
            description: "Send rapid successive requests",
            command: `for i in {1..100}; do curl https://target/api/endpoint & done`,
            expectedResult: "All requests accepted without throttling",
        },
        {
            order: 3,
            action: "verify-no-blocking",
            description: "Verify no rate limiting or IP blocking occurs",
            command: "Continue sending requests and monitor response codes",
            expectedResult: "No 429 Too Many Requests or blocking observed",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Access to API endpoint",
        ],
        steps,
        payload: "Automated script sending 1000+ requests per minute",
        expectedResult: "API abuse, potential DoS, resource exhaustion, or brute force attacks",
        safeTestInstructions: "Test on isolated/staging environment only. Use small request volumes (10-20 requests). Never DoS production systems.",
    };
}
function dataExposurePoC(finding) {
    const steps = [
        {
            order: 1,
            action: "identify-endpoint",
            description: "Identify endpoint returning full objects",
            command: `Review ${finding.file}:${finding.line}`,
            expectedResult: "Endpoint identified",
        },
        {
            order: 2,
            action: "make-request",
            description: "Make normal API request",
            command: `curl -H "Authorization: Bearer TOKEN" https://target/api/users/me`,
            expectedResult: "Response contains excessive data",
        },
        {
            order: 3,
            action: "analyze-response",
            description: "Analyze response for sensitive fields",
            command: "Inspect response JSON for internal fields, IDs, hashes, tokens",
            expectedResult: "Fields like __v, _id, passwordHash, internalId, createdBy exposed",
        },
    ];
    return {
        id: `poc-${finding.id}`,
        findingId: finding.id,
        prerequisites: [
            "Access to API endpoint",
            "Valid authentication",
        ],
        steps,
        payload: "GET /api/resource",
        expectedResult: "Excessive data exposure revealing sensitive or internal fields",
        safeTestInstructions: "Test with your own account. Document exposed fields. Never share or use exposed sensitive data.",
    };
}
// ============================================================================
// Register Tactic
// ============================================================================
registerTactic(apiTactic);
export { apiTactic };
//# sourceMappingURL=api.js.map