js.extract_secrets
Extract potential API keys, tokens, and secrets from JavaScript source code using heuristic analysis for security testing.
Instructions
Heuristically extract potential API keys, tokens, and secrets from JS
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| source | Yes | JavaScript source code |
Implementation Reference
- src/tools/js.ts:144-227 (handler)The main handler function that heuristically extracts potential API keys, tokens, AWS keys, Google API keys, and secret candidates from JavaScript source code using various regex patterns. It categorizes and deduplicates findings and returns a structured result.async ({ source }: any): Promise<ToolResult> => { try { const secrets: any = { apiKeys: [], tokens: [], passwords: [], awsKeys: [], googleKeys: [], candidates: [], }; // API Key patterns const apiKeyPatterns = [ /(?:api[_-]?key|apikey)[\s:=]+["'`]([A-Za-z0-9_\-]{20,})["'`]/gi, /(?:secret[_-]?key|secretkey)[\s:=]+["'`]([A-Za-z0-9_\-]{20,})["'`]/gi, ]; // Token patterns const tokenPatterns = [ /(?:token|access[_-]?token)[\s:=]+["'`]([A-Za-z0-9_\-]{20,})["'`]/gi, /(?:bearer|authorization)[\s:]+["'`]?([A-Za-z0-9_\-\.]{20,})["'`]?/gi, ]; // AWS keys const awsPattern = /AKIA[0-9A-Z]{16}/g; // Google API keys const googlePattern = /AIza[0-9A-Za-z\-_]{35}/g; // Extract matches apiKeyPatterns.forEach((pattern) => { let match: RegExpExecArray | null; while ((match = pattern.exec(source)) !== null) { secrets.apiKeys.push(match[1]); } }); tokenPatterns.forEach((pattern) => { let match: RegExpExecArray | null; while ((match = pattern.exec(source)) !== null) { secrets.tokens.push(match[1]); } }); const awsMatches = source.match(awsPattern) || []; secrets.awsKeys = Array.from(new Set(awsMatches)); const googleMatches = source.match(googlePattern) || []; secrets.googleKeys = Array.from(new Set(googleMatches)); // General long strings that might be secrets const candidatePattern = /["'`]([A-Za-z0-9_\-]{32,})["'`]/g; let candidateMatch: RegExpExecArray | null; while ((candidateMatch = candidatePattern.exec(source)) !== null) { const candidate = candidateMatch[1]; // Filter out URLs and common false positives if ( !candidate.startsWith('http') && !candidate.includes('/') && candidate.length < 200 ) { secrets.candidates.push(candidate); } } // Deduplicate secrets.apiKeys = Array.from(new Set(secrets.apiKeys)); secrets.tokens = Array.from(new Set(secrets.tokens)); secrets.candidates = Array.from(new Set(secrets.candidates)).slice(0, 50); return formatToolResult(true, { ...secrets, summary: { totalApiKeys: secrets.apiKeys.length, totalTokens: secrets.tokens.length, totalAwsKeys: secrets.awsKeys.length, totalGoogleKeys: secrets.googleKeys.length, totalCandidates: secrets.candidates.length, }, }); } catch (error: any) { return formatToolResult(false, null, error.message); } }
- src/tools/js.ts:134-143 (schema)The input schema for the tool, requiring a 'source' string parameter containing the JavaScript code to analyze.{ description: 'Heuristically extract potential API keys, tokens, and secrets from JS', inputSchema: { type: 'object', properties: { source: { type: 'string', description: 'JavaScript source code' }, }, required: ['source'], }, },
- src/tools/js.ts:133-228 (registration)The server.tool() call that registers the 'js.extract_secrets' tool with its schema and inline handler function.'js.extract_secrets', { description: 'Heuristically extract potential API keys, tokens, and secrets from JS', inputSchema: { type: 'object', properties: { source: { type: 'string', description: 'JavaScript source code' }, }, required: ['source'], }, }, async ({ source }: any): Promise<ToolResult> => { try { const secrets: any = { apiKeys: [], tokens: [], passwords: [], awsKeys: [], googleKeys: [], candidates: [], }; // API Key patterns const apiKeyPatterns = [ /(?:api[_-]?key|apikey)[\s:=]+["'`]([A-Za-z0-9_\-]{20,})["'`]/gi, /(?:secret[_-]?key|secretkey)[\s:=]+["'`]([A-Za-z0-9_\-]{20,})["'`]/gi, ]; // Token patterns const tokenPatterns = [ /(?:token|access[_-]?token)[\s:=]+["'`]([A-Za-z0-9_\-]{20,})["'`]/gi, /(?:bearer|authorization)[\s:]+["'`]?([A-Za-z0-9_\-\.]{20,})["'`]?/gi, ]; // AWS keys const awsPattern = /AKIA[0-9A-Z]{16}/g; // Google API keys const googlePattern = /AIza[0-9A-Za-z\-_]{35}/g; // Extract matches apiKeyPatterns.forEach((pattern) => { let match: RegExpExecArray | null; while ((match = pattern.exec(source)) !== null) { secrets.apiKeys.push(match[1]); } }); tokenPatterns.forEach((pattern) => { let match: RegExpExecArray | null; while ((match = pattern.exec(source)) !== null) { secrets.tokens.push(match[1]); } }); const awsMatches = source.match(awsPattern) || []; secrets.awsKeys = Array.from(new Set(awsMatches)); const googleMatches = source.match(googlePattern) || []; secrets.googleKeys = Array.from(new Set(googleMatches)); // General long strings that might be secrets const candidatePattern = /["'`]([A-Za-z0-9_\-]{32,})["'`]/g; let candidateMatch: RegExpExecArray | null; while ((candidateMatch = candidatePattern.exec(source)) !== null) { const candidate = candidateMatch[1]; // Filter out URLs and common false positives if ( !candidate.startsWith('http') && !candidate.includes('/') && candidate.length < 200 ) { secrets.candidates.push(candidate); } } // Deduplicate secrets.apiKeys = Array.from(new Set(secrets.apiKeys)); secrets.tokens = Array.from(new Set(secrets.tokens)); secrets.candidates = Array.from(new Set(secrets.candidates)).slice(0, 50); return formatToolResult(true, { ...secrets, summary: { totalApiKeys: secrets.apiKeys.length, totalTokens: secrets.tokens.length, totalAwsKeys: secrets.awsKeys.length, totalGoogleKeys: secrets.googleKeys.length, totalCandidates: secrets.candidates.length, }, }); } catch (error: any) { return formatToolResult(false, null, error.message); } } );