surfscan 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/types.ts","../src/core/runner.ts","../src/core/text.ts","../src/core/config.ts","../src/core/node-provider.ts","../src/core/secret-patterns.ts","../src/core/report/sanitize.ts","../src/core/report/text.ts","../src/core/report/json.ts","../src/scanners/shared.ts","../src/scanners/rules/patterns.ts","../src/scanners/rules/index.ts","../src/scanners/keys/gitignore.ts","../src/scanners/keys/index.ts","../src/scanners/shared-json.ts","../src/scanners/approvals/adapters/claude-code.ts","../src/scanners/approvals/destructive.ts","../src/scanners/approvals/index.ts","../src/scanners/mcp/tools.ts","../src/scanners/mcp/config.ts","../src/scanners/mcp/known-hosts.json","../src/scanners/mcp/index.ts","../src/scanners/deps/lockfile.ts","../src/scanners/deps/registry.ts","../src/scanners/deps/popular-packages.json","../src/scanners/deps/typosquat.ts","../src/scanners/deps/index.ts"],"sourcesContent":["export type Severity = 'high' | 'medium' | 'low' | 'info';\n\n/** Highest first. */\nexport const SEVERITIES: readonly Severity[] = ['high', 'medium', 'low', 'info'];\n\nexport const SEVERITY_RANK: Record<Severity, number> = {\n high: 3,\n medium: 2,\n low: 1,\n info: 0,\n};\n\nexport function isSeverity(value: unknown): value is Severity {\n return typeof value === 'string' && (SEVERITIES as readonly string[]).includes(value);\n}\n\nexport interface Finding {\n ruleId: string;\n severity: Severity;\n /** What was found. Must never contain a full secret value. */\n message: string;\n /** Path relative to the scan root, always with forward slashes. */\n file: string;\n /** 1-based. 0 means the finding applies to the whole file. */\n line: number;\n /** 1-based. */\n column?: number;\n /** How to fix it. */\n fix: string;\n}\n\nexport interface SurfscanConfig {\n /** Rule IDs to skip. */\n ignore: string[];\n /** Globs (relative to the scan root) to exclude from discovery. */\n ignorePaths: string[];\n deps: {\n minAgeDays: number;\n };\n}\n\n/**\n * Read-only access to the project being scanned. Implemented for Node in\n * `node-provider.ts`; a browser demo or test can supply an in-memory one.\n */\nexport interface SourceProvider {\n /** List files matching the globs, relative to the root, with forward slashes. */\n list(patterns: string[], ignore: string[]): Promise<string[]>;\n /** Read a file relative to the root. Resolves to undefined if it does not exist. */\n read(path: string, opts?: { maxBytes?: number }): Promise<string | undefined>;\n /** Links matched since the last call that were not scanned. Each is returned once. */\n takeSkippedLinks?(): string[];\n}\n\nexport interface SourceFile {\n /** Relative to the scan root, forward slashes. */\n path: string;\n content: string;\n}\n\nexport interface ScanContext {\n files: SourceFile[];\n config: SurfscanConfig;\n provider: SourceProvider;\n /** Scanner-specific options (for example `offline` for deps). */\n options: Readonly<Record<string, unknown>>;\n /**\n * Report a non-fatal problem, such as an unreadable file or a network failure.\n * Pass `incomplete: true` when the problem meant a check could not run, so\n * the result cannot be read as \"nothing found\".\n */\n warn(message: string, opts?: { incomplete?: boolean }): void;\n}\n\nexport interface Rule {\n id: string;\n severity: Severity;\n title: string;\n check(context: ScanContext): Finding[] | Promise<Finding[]>;\n}\n\nexport interface Scanner {\n name: string;\n /** Ordered high to low severity. */\n rules: Rule[];\n findTargets(provider: SourceProvider, config: SurfscanConfig): Promise<string[]>;\n /** Read limit for this scanner's files, when they are routinely larger than the default. */\n maxFileBytes?: number;\n}\n\nexport interface ScanResult {\n findings: Finding[];\n warnings: string[];\n /** True when at least one check could not run (for example the registry was unreachable). */\n incomplete: boolean;\n}\n","import { SEVERITY_RANK } from './types.js';\nimport type {\n Finding,\n Scanner,\n ScanContext,\n ScanResult,\n Severity,\n SourceFile,\n SourceProvider,\n SurfscanConfig,\n} from './types.js';\n\n/** Paths never scanned, in addition to config.ignorePaths. */\nexport const DEFAULT_IGNORE_PATHS = ['**/node_modules/**', '**/.git/**'];\n\nexport interface RunOptions {\n provider: SourceProvider;\n config: SurfscanConfig;\n /** Scanner-specific options, passed through to rules as `context.options`. */\n options?: Record<string, unknown>;\n}\n\nexport function compareFindings(a: Finding, b: Finding): number {\n return (\n SEVERITY_RANK[b.severity] - SEVERITY_RANK[a.severity] ||\n a.file.localeCompare(b.file) ||\n a.line - b.line ||\n (a.column ?? 0) - (b.column ?? 0) ||\n a.ruleId.localeCompare(b.ruleId)\n );\n}\n\nexport function sortFindings(findings: Finding[]): Finding[] {\n return [...findings].sort(compareFindings);\n}\n\n/** Discover target files for a scanner, honouring default and configured ignores. */\nexport function listTargets(\n provider: SourceProvider,\n config: SurfscanConfig,\n patterns: string[],\n extraIgnore: string[] = [],\n): Promise<string[]> {\n return provider.list(patterns, [...DEFAULT_IGNORE_PATHS, ...extraIgnore, ...config.ignorePaths]);\n}\n\nexport async function runScanner(scanner: Scanner, opts: RunOptions): Promise<ScanResult> {\n const warnings: string[] = [];\n let incomplete = false;\n const paths = await scanner.findTargets(opts.provider, opts.config);\n\n for (const link of opts.provider.takeSkippedLinks?.() ?? []) {\n warnings.push(`${link}: not scanned, because surfscan does not follow links to folders or to files outside the project`);\n incomplete = true;\n }\n\n const readOptions = scanner.maxFileBytes === undefined ? undefined : { maxBytes: scanner.maxFileBytes };\n const files: SourceFile[] = [];\n for (const path of paths) {\n try {\n const content = await opts.provider.read(path, readOptions);\n if (content !== undefined) files.push({ path, content });\n } catch (err) {\n warnings.push(`${path}: skipped (${(err as Error).message})`);\n incomplete = true;\n }\n }\n\n const context: ScanContext = {\n files,\n config: opts.config,\n provider: opts.provider,\n options: opts.options ?? {},\n warn: (message, warnOpts) => {\n warnings.push(message);\n if (warnOpts?.incomplete) incomplete = true;\n },\n };\n\n const ignored = new Set(opts.config.ignore);\n const findings: Finding[] = [];\n for (const rule of scanner.rules) {\n if (ignored.has(rule.id)) continue;\n try {\n findings.push(...(await rule.check(context)));\n } catch (err) {\n warnings.push(`${rule.id}: rule failed (${(err as Error).message})`);\n incomplete = true;\n }\n }\n\n return { findings: sortFindings(findings), warnings, incomplete };\n}\n\nexport async function runScanners(scanners: Scanner[], opts: RunOptions): Promise<ScanResult> {\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let incomplete = false;\n for (const scanner of scanners) {\n const result = await runScanner(scanner, opts);\n findings.push(...result.findings);\n warnings.push(...result.warnings);\n incomplete ||= result.incomplete;\n }\n return { findings: sortFindings(findings), warnings, incomplete };\n}\n\nexport function summarize(findings: Finding[]): Record<Severity, number> {\n const summary: Record<Severity, number> = { high: 0, medium: 0, low: 0, info: 0 };\n for (const f of findings) summary[f.severity]++;\n return summary;\n}\n\n/** True when at least one finding is at or above the threshold. */\nexport function hasFailures(findings: Finding[], failOn: Severity): boolean {\n return findings.some((f) => SEVERITY_RANK[f.severity] >= SEVERITY_RANK[failOn]);\n}\n","/** Small text helpers shared by scanners. No Node or CLI dependencies. */\n\nexport interface Position {\n line: number;\n column: number;\n}\n\n/** Maps string offsets to 1-based line and column numbers. */\nexport class LineIndex {\n private readonly starts: number[] = [0];\n\n constructor(private readonly text: string) {\n for (let i = 0; i < text.length; i++) {\n if (text.charCodeAt(i) === 10) this.starts.push(i + 1);\n }\n }\n\n positionOf(offset: number): Position {\n let lo = 0;\n let hi = this.starts.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (this.starts[mid]! <= offset) lo = mid;\n else hi = mid - 1;\n }\n return { line: lo + 1, column: offset - this.starts[lo]! + 1 };\n }\n\n get lineCount(): number {\n return this.starts.length;\n }\n\n /** Line text without the trailing newline (or \\r\\n). */\n lineText(line: number): string {\n const start = this.starts[line - 1];\n if (start === undefined) return '';\n const next = this.starts[line];\n let end = next === undefined ? this.text.length : next - 1;\n if (end > start && this.text.charCodeAt(end - 1) === 13) end--;\n return this.text.slice(start, end);\n }\n\n lineStart(line: number): number {\n return this.starts[line - 1] ?? this.text.length;\n }\n}\n\n/** Drop a leading UTF-8 byte order mark, which JSON.parse rejects. */\nexport function stripBom(text: string): string {\n return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n}\n\n/** Shorten text for display in a finding message. */\nexport function excerpt(text: string, max = 80): string {\n const oneLine = text.replace(/\\s+/g, ' ').trim();\n return oneLine.length > max ? `${oneLine.slice(0, max - 3)}...` : oneLine;\n}\n\nexport function codePointLabel(cp: number): string {\n return `U+${cp.toString(16).toUpperCase().padStart(4, '0')}`;\n}\n","import { stripBom } from './text.js';\nimport type { SurfscanConfig } from './types.js';\n\nexport const CONFIG_FILE_NAME = 'surfscan.json';\n\nexport const DEFAULT_CONFIG: SurfscanConfig = {\n ignore: [],\n ignorePaths: [],\n deps: { minAgeDays: 30 },\n};\n\nexport class ConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigError';\n }\n}\n\nconst TOP_LEVEL_KEYS = ['ignore', 'ignorePaths', 'deps'];\nconst DEPS_KEYS = ['minAgeDays'];\nconst RULE_ID = /^[A-Z]+-\\d{3}$/;\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction checkKeys(obj: Record<string, unknown>, allowed: string[], where: string, source: string): void {\n for (const key of Object.keys(obj)) {\n if (!allowed.includes(key)) {\n throw new ConfigError(\n `${source}: unknown key \"${where}${key}\". Allowed keys: ${allowed.map((k) => where + k).join(', ')}`,\n );\n }\n }\n}\n\nfunction stringArray(value: unknown, name: string, source: string): string[] {\n if (!Array.isArray(value) || !value.every((v) => typeof v === 'string')) {\n throw new ConfigError(`${source}: \"${name}\" must be an array of strings`);\n }\n return value as string[];\n}\n\n/** Validate a parsed config object and merge it over the defaults. */\nexport function validateConfig(raw: unknown, source = CONFIG_FILE_NAME): SurfscanConfig {\n if (!isPlainObject(raw)) {\n throw new ConfigError(`${source}: config must be a JSON object`);\n }\n checkKeys(raw, TOP_LEVEL_KEYS, '', source);\n\n const config: SurfscanConfig = {\n ignore: [...DEFAULT_CONFIG.ignore],\n ignorePaths: [...DEFAULT_CONFIG.ignorePaths],\n deps: { ...DEFAULT_CONFIG.deps },\n };\n\n if (raw.ignore !== undefined) {\n config.ignore = stringArray(raw.ignore, 'ignore', source);\n for (const id of config.ignore) {\n if (!RULE_ID.test(id)) {\n throw new ConfigError(`${source}: \"ignore\" entry \"${id}\" is not a rule ID (expected something like RULES-001)`);\n }\n }\n }\n\n if (raw.ignorePaths !== undefined) {\n config.ignorePaths = stringArray(raw.ignorePaths, 'ignorePaths', source);\n }\n\n if (raw.deps !== undefined) {\n if (!isPlainObject(raw.deps)) {\n throw new ConfigError(`${source}: \"deps\" must be an object`);\n }\n checkKeys(raw.deps, DEPS_KEYS, 'deps.', source);\n const { minAgeDays } = raw.deps;\n if (minAgeDays !== undefined) {\n if (typeof minAgeDays !== 'number' || !Number.isInteger(minAgeDays) || minAgeDays < 0) {\n throw new ConfigError(`${source}: \"deps.minAgeDays\" must be a non-negative integer`);\n }\n config.deps.minAgeDays = minAgeDays;\n }\n }\n\n return config;\n}\n\n/** Parse and validate the text of a surfscan.json file. */\nexport function parseConfig(text: string, source = CONFIG_FILE_NAME): SurfscanConfig {\n let raw: unknown;\n try {\n raw = JSON.parse(stripBom(text));\n } catch (err) {\n throw new ConfigError(`${source}: invalid JSON (${(err as Error).message})`);\n }\n return validateConfig(raw, source);\n}\n\n/**\n * Load a config file through the given reader. Resolves to the defaults when\n * the file does not exist and `required` is false.\n */\nexport async function loadConfig(\n read: (path: string) => Promise<string | undefined>,\n path: string,\n required: boolean,\n): Promise<SurfscanConfig> {\n const text = await read(path);\n if (text === undefined) {\n if (required) throw new ConfigError(`config file not found: ${path}`);\n return validateConfig({});\n }\n return parseConfig(text, path);\n}\n","import { readFile, realpath, stat } from 'node:fs/promises';\nimport { isAbsolute, join, relative, sep } from 'node:path';\nimport fg from 'fast-glob';\nimport type { SourceProvider } from './types.js';\n\n/** Files larger than this are skipped with a warning, unless the scanner sets its own limit. */\nexport const MAX_FILE_BYTES = 2 * 1024 * 1024;\n\n/** Folders that agents read as a whole, so a link to one matters even though no file pattern can match it. */\nconst AGENT_FOLDERS = '**/.{claude,codex,cursor,github,surfscan,vscode}';\n\nconst UTF16_LE = [0xff, 0xfe];\nconst UTF16_BE = [0xfe, 0xff];\nconst startsWith = (bytes: Buffer, mark: number[]): boolean => mark.every((b, i) => bytes[i] === b);\n\n/** Windows PowerShell 5.1 writes UTF-16 with `>`, and agents read those files fine, so surfscan must too. */\nfunction decode(bytes: Buffer): string {\n if (startsWith(bytes, UTF16_LE)) return new TextDecoder('utf-16le').decode(bytes);\n if (startsWith(bytes, UTF16_BE)) return new TextDecoder('utf-16be').decode(bytes);\n return bytes.toString('utf8');\n}\n\n/** Read-only file access rooted at a directory on disk. */\nexport function createNodeProvider(root: string): SourceProvider {\n const pendingLinks = new Set<string>();\n const reportedLinks = new Set<string>();\n\n /**\n * Links are not followed, so a link matching `patterns` would be missed without\n * a trace. A link to a file inside the project is read like any other file; it\n * adds nothing if its target is scanned anyway. Anything else is reported.\n */\n async function resolveLinks(patterns: string[], ignore: string[], paths: string[]): Promise<string[]> {\n const entries = await fg([...patterns, AGENT_FOLDERS], {\n cwd: root,\n dot: true,\n onlyFiles: false,\n objectMode: true,\n followSymbolicLinks: false,\n suppressErrors: true,\n ignore,\n });\n const realRoot = await realpath(root);\n const extra: string[] = [];\n for (const entry of entries) {\n if (!entry.dirent.isSymbolicLink() || paths.includes(entry.path)) continue;\n let target: string;\n let isFile: boolean;\n try {\n target = await realpath(join(root, entry.path));\n isFile = (await stat(target)).isFile();\n } catch {\n continue; // A broken link has nothing to scan.\n }\n const inside = relative(realRoot, target);\n if (isFile && !isAbsolute(inside) && !inside.startsWith(`..${sep}`)) {\n if (!paths.includes(inside.split(sep).join('/'))) extra.push(entry.path);\n } else if (!reportedLinks.has(entry.path)) {\n reportedLinks.add(entry.path);\n pendingLinks.add(entry.path);\n }\n }\n return extra;\n }\n\n return {\n async list(patterns, ignore) {\n const paths = await fg(patterns, {\n cwd: root,\n dot: true,\n onlyFiles: true,\n unique: true,\n followSymbolicLinks: false,\n suppressErrors: true,\n ignore,\n });\n return [...paths, ...(await resolveLinks(patterns, ignore, paths))].sort();\n },\n\n async read(path, opts) {\n const abs = join(root, path);\n const limit = opts?.maxBytes ?? MAX_FILE_BYTES;\n try {\n const info = await stat(abs);\n if (!info.isFile()) return undefined;\n if (info.size > limit) {\n throw new Error(`larger than ${limit} bytes`);\n }\n return decode(await readFile(abs));\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined;\n throw err;\n }\n },\n\n takeSkippedLinks() {\n const links = [...pendingLinks];\n pendingLinks.clear();\n return links;\n },\n };\n}\n","/**\n * Patterns for well-known secret formats. Used by the report layer as a last\n * line of defence against printing a secret, and by the keys scanner.\n */\nexport interface SecretPattern {\n name: string;\n regex: RegExp;\n}\n\nexport const SECRET_PATTERNS: readonly SecretPattern[] = [\n { name: 'AWS access key ID', regex: /\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\b/g },\n { name: 'Stripe live key', regex: /\\b(?:sk|rk)_live_[0-9A-Za-z]{10,}\\b/g },\n { name: 'GitHub token', regex: /\\b(?:ghp|gho|ghu|ghs|ghr)_[0-9A-Za-z]{30,}\\b/g },\n { name: 'GitHub fine-grained token', regex: /\\bgithub_pat_[0-9A-Za-z_]{30,}\\b/g },\n { name: 'Slack token', regex: /\\bxox[abposr]-[0-9A-Za-z-]{10,}\\b/g },\n { name: 'Anthropic API key', regex: /\\bsk-ant-[0-9A-Za-z_-]{20,}/g },\n { name: 'OpenAI API key', regex: /\\bsk-(?:proj|svcacct|admin)-[0-9A-Za-z_-]{20,}|\\bsk-[0-9A-Za-z]{32,}\\b/g },\n { name: 'Google API key', regex: /\\bAIza[0-9A-Za-z_-]{35}(?![0-9A-Za-z_-])/g },\n { name: 'npm token', regex: /\\bnpm_[0-9A-Za-z]{36}\\b/g },\n { name: 'GitLab token', regex: /\\bglpat-[0-9A-Za-z_-]{20,}/g },\n { name: 'Hugging Face token', regex: /\\bhf_[0-9A-Za-z]{30,}\\b/g },\n { name: 'SendGrid API key', regex: /\\bSG\\.[0-9A-Za-z_-]{22}\\.[0-9A-Za-z_-]{43}(?![0-9A-Za-z_-])/g },\n { name: 'JSON Web Token', regex: /\\beyJ[0-9A-Za-z_-]{8,}\\.eyJ[0-9A-Za-z_-]{8,}\\.[0-9A-Za-z_-]{8,}/g },\n {\n name: 'PEM private key',\n regex: /-----BEGIN (?:[A-Z]+ )*PRIVATE KEY-----[\\s\\S]*?(?:-----END (?:[A-Z]+ )*PRIVATE KEY-----|$)/g,\n },\n];\n\nconst HIDDEN = '[redacted]';\n\n/** Values that name a secret rather than hold one, or are already masked. */\nconst NOT_A_VALUE = /^(?:\\$|<|\\{|%)|\\.\\.\\.$|^\\[redacted\\]$/;\n\n/**\n * Secrets found by what surrounds them. Each pattern captures the text to keep\n * and the value to hide. These only shape what is printed, so masking a harmless\n * word (\"password is required\") costs nothing, unlike printing a real password.\n */\nconst SECRET_IN_CONTEXT: readonly RegExp[] = [\n // Authorization: Bearer x. First, or the next pattern would take \"Bearer\" for the value.\n /(\\b(?:Bearer|Basic|Token)\\s+)([A-Za-z0-9._~+/=-]{8,})/g,\n // password=x \"api_key\": \"x\" the token is x\n /(\\b[\\w-]*(?:password|passwd|pwd|secret|token|api[_-]?key|credential|auth)[\\w-]*[\"']?\\s*(?:=|:|\\s(?:is|was)\\s)\\s*[\"']?)([^\\s\"',;)]{4,})/gi,\n // --token x --password=x\n /(--[\\w-]*(?:password|passwd|token|api-?key|secret|auth)[\\w-]*[= ]+[\"']?)([^\\s\"',;)]{4,})/gi,\n // curl -u user:password\n /((?:^|\\s)(?:-u|--user)[ =]+[\"']?[^\\s:\"']+:)([^\\s\"']+)/g,\n // https://user:password@host\n /(:\\/\\/[^\\s:/@]+:)([^\\s@/]+)(?=@)/g,\n];\n\n/** A long token mixing upper case, lower case and digits. Next to a slash it is a path segment, so it stays. */\nconst OPAQUE_TOKEN = /(?<![\\w+/-])[A-Za-z0-9_+-]{32,}(?![\\w+/-])/g;\n\nfunction hideOpaqueToken(token: string): string {\n return /[A-Z]/.test(token) && /[a-z]/.test(token) && /\\d/.test(token) ? maskSecret(token) : token;\n}\n\n/** Mask a secret value: first 4 characters, then \"...\". */\nexport function maskSecret(value: string): string {\n return `${value.slice(0, 4)}...`;\n}\n\n/** Replace anything that looks like a secret in text about to be printed. */\nexport function redactSecrets(text: string): string {\n let out = text;\n for (const { regex } of SECRET_PATTERNS) {\n out = out.replace(new RegExp(regex.source, regex.flags), (m) => maskSecret(m));\n }\n for (const regex of SECRET_IN_CONTEXT) {\n out = out.replace(new RegExp(regex.source, regex.flags), (whole, keep: string, value: string) =>\n NOT_A_VALUE.test(value) ? whole : `${keep}${HIDDEN}`,\n );\n }\n return out.replace(OPAQUE_TOKEN, hideOpaqueToken);\n}\n","import { redactSecrets } from '../secret-patterns.js';\nimport type { Finding } from '../types.js';\n\n// C0 controls (except tab), DEL, C1 controls, and invisible or bidirectional\n// format characters. Printing these raw would let a scanned file rewrite the\n// terminal (ANSI escapes) or reorder the report text (bidi overrides).\nconst UNSAFE = /[\\u0000-\\u0008\\u000A-\\u001F\\u007F-\\u009F­؜᠎​-‏‪-‮⁠-⁤⁦-⁩]|[\\u{E0000}-\\u{E007F}]/gu;\n\n/** Make text safe to print on a terminal: escape control and invisible characters. */\nexport function escapeUnsafe(text: string): string {\n return text.replace(UNSAFE, (ch) => {\n const cp = ch.codePointAt(0)!;\n return cp > 0xffff ? `\\\\u{${cp.toString(16).toUpperCase()}}` : `\\\\u${cp.toString(16).toUpperCase().padStart(4, '0')}`;\n });\n}\n\n/** Mask secrets in every text field of a finding. Applied to all output formats. */\nexport function redactFinding(f: Finding): Finding {\n return {\n ...f,\n message: redactSecrets(f.message),\n fix: redactSecrets(f.fix),\n file: redactSecrets(f.file),\n };\n}\n","import { summarize } from '../runner.js';\nimport { SEVERITIES } from '../types.js';\nimport type { Finding, Severity } from '../types.js';\nimport { escapeUnsafe, redactFinding } from './sanitize.js';\n\nexport interface TextOptions {\n color: boolean;\n /** A check could not run; say so under the summary. */\n incomplete?: boolean;\n}\n\nconst COLORS: Record<Severity, string> = {\n high: '\\u001b[31m', // red\n medium: '\\u001b[33m', // yellow\n low: '\\u001b[36m', // cyan\n info: '\\u001b[90m', // grey\n};\nconst RESET = '\\u001b[0m';\nconst DIM = '\\u001b[2m';\n\nfunction location(f: Finding): string {\n return f.line > 0 ? `${f.file}:${f.line}` : f.file;\n}\n\nexport function summaryLine(findings: Finding[]): string {\n if (findings.length === 0) return 'No findings';\n const summary = summarize(findings);\n const parts = SEVERITIES.filter((s) => summary[s] > 0).map((s) => `${summary[s]} ${s}`);\n const noun = findings.length === 1 ? 'finding' : 'findings';\n return `${findings.length} ${noun} (${parts.join(', ')})`;\n}\n\n/** Findings must already be sorted. */\nexport function formatText(findings: Finding[], opts: TextOptions): string {\n const safe = findings.map((f) => {\n const r = redactFinding(f);\n return { ...r, file: escapeUnsafe(r.file), message: escapeUnsafe(r.message), fix: escapeUnsafe(r.fix) };\n });\n\n const locWidth = Math.max(0, ...safe.map((f) => location(f).length));\n const idWidth = Math.max(0, ...safe.map((f) => f.ruleId.length));\n\n const lines: string[] = [];\n for (const f of safe) {\n // \"MEDIUM\" is the longest label; pad so rule IDs line up.\n const sev = `${f.severity.toUpperCase().padEnd(6)} `;\n const sevText = opts.color ? `${COLORS[f.severity]}${sev}${RESET}` : sev;\n lines.push(`${location(f).padEnd(locWidth)} ${sevText}${f.ruleId.padEnd(idWidth)} ${f.message}`);\n lines.push(opts.color ? ` ${DIM}Fix: ${f.fix}${RESET}` : ` Fix: ${f.fix}`);\n }\n lines.push(summaryLine(findings));\n if (opts.incomplete) lines.push('Incomplete: some checks could not run, so this result is not a clean bill of health (see the warnings)');\n return `${lines.join('\\n')}\\n`;\n}\n","import { summarize } from '../runner.js';\nimport type { Finding, Severity } from '../types.js';\nimport { redactSecrets } from '../secret-patterns.js';\nimport { escapeUnsafe, redactFinding } from './sanitize.js';\n\nexport const JSON_REPORT_VERSION = 1;\n\nexport interface JsonReport {\n version: number;\n summary: Record<Severity, number>;\n /** False when a check could not run, so an empty `findings` does not mean clean. */\n complete: boolean;\n warnings: string[];\n findings: Finding[];\n}\n\nexport interface ReportMeta {\n warnings?: string[];\n incomplete?: boolean;\n}\n\nexport function toJsonReport(findings: Finding[], meta: ReportMeta = {}): JsonReport {\n return {\n version: JSON_REPORT_VERSION,\n summary: summarize(findings),\n complete: !meta.incomplete,\n warnings: (meta.warnings ?? []).map((w) => escapeUnsafe(redactSecrets(w))),\n findings: findings.map((f) => {\n const r = redactFinding(f);\n // Fixed key order keeps output stable for diffing.\n const out: Finding =\n r.column === undefined\n ? { ruleId: r.ruleId, severity: r.severity, message: r.message, file: r.file, line: r.line, fix: r.fix }\n : { ruleId: r.ruleId, severity: r.severity, message: r.message, file: r.file, line: r.line, column: r.column, fix: r.fix };\n return out;\n }),\n };\n}\n\nexport function formatJson(findings: Finding[], meta: ReportMeta = {}): string {\n return `${JSON.stringify(toJsonReport(findings, meta), null, 2)}\\n`;\n}\n","import { LineIndex } from '../core/text.js';\nimport type { Finding, Rule, SourceFile } from '../core/types.js';\n\n/** A match inside some text, before it is mapped to a file position. */\nexport interface TextMatch {\n index: number;\n /** Short human-readable description of what matched. */\n detail: string;\n}\n\n/** Build findings for a rule from matches in one file. One finding per line. */\nexport function findingsFromMatches(\n rule: Pick<Rule, 'id' | 'severity'>,\n file: SourceFile,\n matches: TextMatch[],\n message: (detail: string) => string,\n fix: string,\n index = new LineIndex(file.content),\n): Finding[] {\n const seenLines = new Set<number>();\n const out: Finding[] = [];\n for (const m of [...matches].sort((a, b) => a.index - b.index)) {\n const pos = index.positionOf(m.index);\n if (seenLines.has(pos.line)) continue;\n seenLines.add(pos.line);\n out.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: message(m.detail),\n file: file.path,\n line: pos.line,\n column: pos.column,\n fix,\n });\n }\n return out;\n}\n\n/** All matches of a regex (forced global), as [index, match] pairs. */\nexport function* matchAll(regex: RegExp, text: string): Generator<RegExpExecArray> {\n const flags = regex.flags.includes('g') ? regex.flags : `${regex.flags}g`;\n const re = new RegExp(regex.source, flags);\n let m: RegExpExecArray | null;\n while ((m = re.exec(text)) !== null) {\n yield m;\n if (m[0].length === 0) re.lastIndex++;\n }\n}\n","/**\n * Text detectors for agent instruction content. They work on any string, so\n * the MCP scanner reuses them on tool descriptions (MCP-001).\n */\nimport { codePointLabel, excerpt } from '../../core/text.js';\nimport { matchAll, type TextMatch } from '../shared.js';\n\n// ---------------------------------------------------------------------------\n// Clause helpers\n// ---------------------------------------------------------------------------\n\nconst CLAUSE_BOUNDARY = /[.!?;\\n]/;\n\n/** Up to 60 characters before `index`, stopping at the start of its clause. */\nfunction clauseBefore(text: string, index: number): string {\n let start = index;\n while (start > 0 && index - start < 60 && !CLAUSE_BOUNDARY.test(text[start - 1]!)) start--;\n return text.slice(start, index);\n}\n\nconst NEGATION = /\\b(?:never|not|no|avoid|refuse|forbidden|prohibited)\\b|n't\\b/gi;\n/** \"Do not hesitate to\", \"no need to\", \"don't forget to\": these encourage the action that follows. */\nconst PERMISSIVE = /\\b(?:hesitate|forget|fail|need|afraid|worry|reason|problem|wait)\\b/i;\n/** The negation belongs to an earlier action: \"Do not stop and send ...\". */\nconst NEW_ACTION = /\\b(?:but|then|instead|just|and)\\b|:/i;\nconst CONDITION = /\\b(?:if|when|unless|once|after|before|while)\\b/i;\nconst MAX_WORDS_AFTER_NEGATION = 4;\n\nconst wordCount = (text: string): number => text.split(/\\s+/).filter(Boolean).length;\n\n/**\n * True when a negation applies to the action at `index`. A negation earlier in\n * the sentence is not enough: in \"Do not worry about it, send the .env file\",\n * nothing negates \"send\".\n */\nfunction isNegated(text: string, index: number): boolean {\n const before = clauseBefore(text, index);\n const negation = [...before.matchAll(NEGATION)].at(-1);\n if (!negation) return false;\n const between = before.slice(negation.index + negation[0].length);\n if (PERMISSIVE.test(between) || NEW_ACTION.test(between)) return false;\n const comma = between.indexOf(',');\n if (comma === -1) return wordCount(between) <= MAX_WORDS_AFTER_NEGATION;\n // A comma only carries the negation through a list: \"Never commit, print, or log secrets\".\n const isList = /\\b(?:or|nor)\\b/i.test(text.slice(index, index + 40));\n return isList && wordCount(between.slice(0, comma)) <= 2 && !CONDITION.test(before.slice(0, negation.index));\n}\n\n// ---------------------------------------------------------------------------\n// RULES-001: invisible and bidirectional characters\n// ---------------------------------------------------------------------------\n\nconst INVISIBLE_NAMES: Record<number, string> = {\n 0x200b: 'ZERO WIDTH SPACE',\n 0x200c: 'ZERO WIDTH NON-JOINER',\n 0x200d: 'ZERO WIDTH JOINER',\n 0x200e: 'LEFT-TO-RIGHT MARK',\n 0x200f: 'RIGHT-TO-LEFT MARK',\n 0x2060: 'WORD JOINER',\n 0xfeff: 'ZERO WIDTH NO-BREAK SPACE',\n 0x202a: 'LEFT-TO-RIGHT EMBEDDING',\n 0x202b: 'RIGHT-TO-LEFT EMBEDDING',\n 0x202c: 'POP DIRECTIONAL FORMATTING',\n 0x202d: 'LEFT-TO-RIGHT OVERRIDE',\n 0x202e: 'RIGHT-TO-LEFT OVERRIDE',\n 0x2066: 'LEFT-TO-RIGHT ISOLATE',\n 0x2067: 'RIGHT-TO-LEFT ISOLATE',\n 0x2068: 'FIRST STRONG ISOLATE',\n 0x2069: 'POP DIRECTIONAL ISOLATE',\n};\n\n// Unicode tag characters (U+E0000 to U+E007F) are also invisible and can\n// spell out a full hidden ASCII message (\"ASCII smuggling\").\nconst INVISIBLE = /[\\u200B-\\u200F\\u2060\\uFEFF\\u202A-\\u202E\\u2066-\\u2069]|[\\u{E0000}-\\u{E007F}]/gu;\nconst TAG_RUN = /[\\u{E0000}-\\u{E007F}]+/gu;\nconst BEFORE_EMOJI_JOINER = /(?:\\p{Extended_Pictographic}|\\uFE0F|[\\u{1F3FB}-\\u{1F3FF}])$/u;\nconst AFTER_EMOJI_JOINER = /^\\p{Extended_Pictographic}/u;\n\n/** A zero width joiner between emoji builds one visible emoji, such as a family. It hides nothing. */\nfunction isEmojiJoiner(text: string, index: number): boolean {\n return (\n text.charCodeAt(index) === 0x200d &&\n BEFORE_EMOJI_JOINER.test(text.slice(Math.max(0, index - 4), index)) &&\n AFTER_EMOJI_JOINER.test(text.slice(index + 1, index + 3))\n );\n}\n\nexport interface InvisibleMatch extends TextMatch {\n codePoints: number[];\n}\n\n/** One match per line, listing the distinct invisible characters found on it. */\nexport function findInvisibleChars(text: string): InvisibleMatch[] {\n const byLine = new Map<number, InvisibleMatch>();\n let lineNo = 0;\n let lastScanned = 0;\n for (const m of matchAll(INVISIBLE, text)) {\n // A UTF-8 byte order mark at the very start of a file is an encoding\n // artefact (common from Windows editors), not hidden content.\n if (m.index === 0 && m[0] === '\\uFEFF') continue;\n if (isEmojiJoiner(text, m.index)) continue;\n for (let i = lastScanned; i < m.index; i++) if (text.charCodeAt(i) === 10) lineNo++;\n lastScanned = m.index;\n const cp = m[0].codePointAt(0)!;\n const existing = byLine.get(lineNo);\n if (existing) {\n if (!existing.codePoints.includes(cp)) existing.codePoints.push(cp);\n } else {\n byLine.set(lineNo, { index: m.index, detail: '', codePoints: [cp] });\n }\n }\n\n const out = [...byLine.values()];\n for (const match of out) {\n const tags = match.codePoints.filter((cp) => cp >= 0xe0000);\n const named = match.codePoints\n .filter((cp) => cp < 0xe0000)\n .map((cp) => `${codePointLabel(cp)} ${INVISIBLE_NAMES[cp] ?? ''}`.trim());\n const parts = [...named];\n if (tags.length > 0) {\n const lineEnd = text.indexOf('\\n', match.index);\n const lineText = text.slice(match.index, lineEnd === -1 ? undefined : lineEnd);\n const decoded = [...lineText.matchAll(TAG_RUN)]\n .map((r) => [...r[0]].map((ch) => decodeTag(ch.codePointAt(0)!)).join(''))\n .join(' ');\n parts.push(`Unicode tag characters decoding to \"${excerpt(decoded, 60)}\"`);\n }\n match.detail = parts.join(', ');\n }\n return out;\n}\n\nfunction decodeTag(cp: number): string {\n const ascii = cp - 0xe0000;\n return ascii >= 0x20 && ascii < 0x7f ? String.fromCharCode(ascii) : '';\n}\n\n// ---------------------------------------------------------------------------\n// RULES-002: hidden comments and markup\n// ---------------------------------------------------------------------------\n\n/**\n * Words that make hidden text look like an instruction to an agent. Hyphens\n * count as part of a word so tool markers such as `prettier-ignore` or\n * `markdownlint-disable` do not match.\n */\nconst DIRECTIVE =\n /(?<![-\\w])(?:you (?:must|should|are|will|need to|have to)|ignore|disregard|forget|pretend|instructions?|assistant|agents?|ai|llm|claude|copilot|cursor|codex|gemini|system prompt|run|execute|install|download|upload|send|post|fetch|curl|wget|delete|exfiltrate|secrets?|passwords?|tokens?|credentials?|api[ _-]?keys?|ssh|(?:do not|don't|never) (?:tell|mention|reveal|inform))(?![-\\w])|\\.env\\b/i;\n\nconst HTML_COMMENT = /<!--([\\s\\S]*?)(?:-->|$)/g;\n// Markdown link reference definitions used as comments: [//]: # (text)\nconst MD_COMMENT = /^[ \\t]*\\[(?:\\/\\/|comment|_)\\]:\\s*(?:#|<>)\\s*(?:\\((.*)\\)|\"(.*)\"|'(.*)')[ \\t]*$/gim;\nconst TAG_NAME = /[a-z][a-z0-9-]*\\b/iy;\nconst HIDDEN_ATTRIBUTE = /\\shidden(?=[\\s/>=])/i;\nconst STYLE_ATTRIBUTE = /\\sstyle\\s*=\\s*([\"'])/gi;\nconst HIDING_STYLE = /display\\s*:\\s*none|visibility\\s*:\\s*hidden|font-size\\s*:\\s*0(?![.\\d]*[1-9])|opacity\\s*:\\s*0(?![.\\d]*[1-9])/i;\n\n/** Offset of the `>` closing a tag, ignoring any inside a quoted attribute. */\nfunction tagEnd(text: string, from: number): number {\n let quote = '';\n for (let i = from; i < text.length; i++) {\n const ch = text[i]!;\n if (quote) {\n if (ch === quote) quote = '';\n } else if (ch === '\"' || ch === \"'\") {\n quote = ch;\n } else if (ch === '>') {\n return i;\n }\n }\n // An unclosed quote: fall back to the first `>`.\n return text.indexOf('>', from);\n}\n\nfunction hidesContent(tag: string): boolean {\n if (HIDDEN_ATTRIBUTE.test(tag)) return true;\n STYLE_ATTRIBUTE.lastIndex = 0;\n let m: RegExpExecArray | null;\n while ((m = STYLE_ATTRIBUTE.exec(tag)) !== null) {\n const close = tag.indexOf(m[1]!, STYLE_ATTRIBUTE.lastIndex);\n const value = tag.slice(STYLE_ATTRIBUTE.lastIndex, close === -1 ? undefined : close);\n if (HIDING_STYLE.test(value)) return true;\n if (close === -1) return false;\n STYLE_ATTRIBUTE.lastIndex = close + 1;\n }\n return false;\n}\n\n/** Walks each tag once, so input with many unclosed tags stays linear. */\nfunction findHiddenTags(text: string): TextMatch[] {\n const out: TextMatch[] = [];\n let at = text.indexOf('<');\n while (at !== -1) {\n TAG_NAME.lastIndex = at + 1;\n if (!TAG_NAME.test(text)) {\n at = text.indexOf('<', at + 1);\n continue;\n }\n const end = tagEnd(text, TAG_NAME.lastIndex);\n if (end === -1) break;\n const tag = text.slice(at, end + 1);\n if (hidesContent(tag)) out.push({ index: at, detail: `hidden markup: ${excerpt(tag, 60)}` });\n at = text.indexOf('<', end + 1);\n }\n return out;\n}\n\nexport function findHiddenContent(text: string): TextMatch[] {\n const out: TextMatch[] = [];\n for (const m of matchAll(HTML_COMMENT, text)) {\n const body = m[1] ?? '';\n if (DIRECTIVE.test(body)) {\n out.push({ index: m.index, detail: `HTML comment: \"${excerpt(body, 60)}\"` });\n }\n }\n for (const m of matchAll(MD_COMMENT, text)) {\n const body = m[1] ?? m[2] ?? m[3] ?? '';\n if (DIRECTIVE.test(body)) {\n out.push({ index: m.index, detail: `Markdown comment: \"${excerpt(body, 60)}\"` });\n }\n }\n out.push(...findHiddenTags(text));\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// RULES-003: download piped into a shell\n// ---------------------------------------------------------------------------\n\nconst SHELLS = '(?:sudo\\\\s+)?(?:ba|z|k|da|fi)?sh|python[0-9.]*|node|perl|ruby|pwsh|powershell|iex|invoke-expression';\nconst DOWNLOADER = /\\b(?:curl|wget|iwr|irm|invoke-webrequest|invoke-restmethod)\\b/gi;\nconst INTO_SHELL = new RegExp(`\\\\|\\\\s*(?:${SHELLS})\\\\b`, 'iy');\nconst SHELL_AROUND_DOWNLOAD = new RegExp(\n [\n // bash <(curl ...) sh -c \"$(curl ...)\"\n `\\\\b(?:(?:ba|z|k|da)?sh|source)\\\\s+(?:-c\\\\s+)?[\"']?(?:<\\\\(|\\\\$\\\\()\\\\s*(?:curl|wget)\\\\b`,\n // iex (iwr ...) Invoke-Expression (New-Object Net.WebClient).DownloadString(...)\n `\\\\b(?:iex|invoke-expression)\\\\s*(?:\\\\(\\\\s*){0,2}(?:iwr|irm|invoke-webrequest|invoke-restmethod|new-object\\\\s+net\\\\.webclient)\\\\b`,\n ].join('|'),\n 'gi',\n);\n\n/** `curl ... | sh`, including `curl ... | tee x | sh`. Each line is walked once, however many downloaders it has. */\nfunction findDownloadPipes(text: string): TextMatch[] {\n const out: TextMatch[] = [];\n const downloader = new RegExp(DOWNLOADER.source, DOWNLOADER.flags);\n let m: RegExpExecArray | null;\n while ((m = downloader.exec(text)) !== null) {\n let i = m.index + m[0].length;\n let found = false;\n for (; i < text.length && text[i] !== '\\n'; i++) {\n if (text[i] !== '|') continue;\n // `curl x || bash fallback` runs bash on failure; it does not pipe the download.\n if (text[i + 1] === '|') {\n i++;\n continue;\n }\n INTO_SHELL.lastIndex = i;\n const shell = INTO_SHELL.exec(text);\n if (shell) {\n i += shell[0].length;\n out.push({ index: m.index, detail: excerpt(text.slice(m.index, i), 70) });\n found = true;\n break;\n }\n }\n downloader.lastIndex = found ? i : i + 1;\n }\n return out;\n}\n\nexport function findPipeToShell(text: string): TextMatch[] {\n const around = [...matchAll(SHELL_AROUND_DOWNLOAD, text)].map((m) => ({ index: m.index, detail: excerpt(m[0], 70) }));\n return [...findDownloadPipes(text), ...around].sort((a, b) => a.index - b.index);\n}\n\n// ---------------------------------------------------------------------------\n// RULES-004: reading or sending credentials\n// ---------------------------------------------------------------------------\n\nconst CRED_VERBS =\n 'read|cat|open|print|output|echo|display|show|reveal|include|send|post|upload|exfiltrate|transmit|forward|copy|paste|share|e-?mail|leak|dump|collect|log|attach|embed|base64|curl|submit|report|grab|extract|access';\nconst CRED_TARGETS = [\n '\\\\.env(?!\\\\.(?:example|sample|template|dist)\\\\b)(?:\\\\.[\\\\w-]+)*\\\\b',\n 'env(?:ironment)? files?',\n 'environment variables',\n 'process\\\\.env',\n '~?/?\\\\.ssh\\\\b',\n 'id_(?:rsa|dsa|ecdsa|ed25519)',\n 'ssh keys?',\n 'private keys?',\n '\\\\.aws/credentials',\n 'aws credentials',\n '\\\\.npmrc',\n '\\\\.netrc',\n '\\\\.pypirc',\n '\\\\.git-credentials',\n '\\\\.docker/config\\\\.json',\n '\\\\.kube/config',\n 'kubeconfig',\n 'credentials?',\n 'secrets?',\n 'api[ _-]?keys?',\n '(?:access|auth|bearer|session|github|npm|api) ?tokens?',\n 'passwords?',\n].join('|');\n\nconst CRED_ACCESS = new RegExp(`\\\\b(?:${CRED_VERBS})\\\\b[^.!?;\\\\n]{0,60}?(?:${CRED_TARGETS})`, 'gi');\nconst ENV_DUMP = /\\b(?:printenv|env|set)\\s*\\|\\s*(?:curl|wget|nc|netcat)\\b/gi;\n\n/** \"Log in with your password\", \"Open a PR to rotate secrets\": the verb is not acting on the credential. */\nconst UNRELATED_VERB = /^(?:log\\s+(?:in|on|out)\\b|open\\s+(?:a|an|the)\\s+(?:pr|pull request|mr|merge request|issue|ticket)\\b)/i;\n/** \"Show an error when the API key is missing\": the credential is only a condition. */\nconst ONLY_A_CONDITION = /\\b(?:when|if|unless|whether)\\b/i;\nconst CRED_STATE_AFTER = /^\\s+(?:is|are)\\s+(?:missing|invalid|expired|required|empty|unset|not set|wrong|incorrect)\\b/i;\n/** \"Read the API key from environment variables\" is the recommended way to configure a key. */\nconst FROM_ENVIRONMENT_AFTER = /^\\s+from\\s+(?:the\\s+|your\\s+)?(?:environment(?:\\s+variables?)?|env\\s+vars?|process\\.env)\\b/i;\nconst FROM_ENVIRONMENT_END = /\\b(?:from|via|using|through)\\s+(?:the\\s+|your\\s+)?(?:environment variables|process\\.env)$/i;\nconst SENDS_IT_ON = /\\b(?:send|post|upload|exfiltrate|transmit|forward|curl|share|e-?mail)\\b|https?:/i;\n\nfunction isBenignCredentialMention(text: string, match: string, index: number): boolean {\n if (UNRELATED_VERB.test(match) || ONLY_A_CONDITION.test(match)) return true;\n const end = index + match.length;\n const after = text.slice(end, end + 120).split(/[.!?;\\n]/, 1)[0]!;\n if (CRED_STATE_AFTER.test(after)) return true;\n return (FROM_ENVIRONMENT_END.test(match) || FROM_ENVIRONMENT_AFTER.test(after)) && !SENDS_IT_ON.test(after);\n}\n\nexport function findCredentialAccess(text: string): TextMatch[] {\n const out: TextMatch[] = [];\n for (const m of matchAll(CRED_ACCESS, text)) {\n if (isNegated(text, m.index) || isBenignCredentialMention(text, m[0], m.index)) continue;\n // \"Copy .env.example to .env\" sets up a local file; it does not read secrets.\n if (/\\.env\\.(?:example|sample|template|dist)\\b/i.test(m[0])) continue;\n out.push({ index: m.index, detail: excerpt(m[0], 70) });\n }\n for (const m of matchAll(ENV_DUMP, text)) {\n out.push({ index: m.index, detail: excerpt(m[0], 70) });\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// RULES-005: override earlier instructions, skip confirmation, hide actions\n// ---------------------------------------------------------------------------\n\nconst OVERRIDE = [\n // ignore previous instructions / disregard the system prompt\n /\\b(?:ignore|disregard|forget|override|bypass)\\b[^.!?;\\n]{0,30}?\\b(?:previous|prior|earlier|above|preceding|system|safety|original|your|initial)\\b[^.!?;\\n]{0,20}?\\b(?:instructions?|rules|prompts?|guidelines|directives?|guardrails|polic(?:y|ies)|constraints|restrictions|messages?|context)\\b/gi,\n // ignore all instructions\n /\\b(?:ignore|disregard|forget)\\s+(?:all|any)\\s+(?:other\\s+)?(?:instructions|prompts|directives|guidelines)\\b/gi,\n];\n\n/** Negating these makes a safeguard: \"Never skip confirmation\", \"Do not use --yolo\". */\nconst DISABLE_SAFEGUARD = [\n ...OVERRIDE,\n // skip confirmation / bypass approval\n /\\b(?:skip|bypass|disable|turn off)\\b[^.!?;\\n]{0,20}?\\b(?:confirmations?|approvals?|permission (?:checks?|prompts?)|safety checks?|human review|review step)\\b/gi,\n // flags and modes that turn off prompts\n /--dangerously-skip-permissions\\b|\\bbypassPermissions\\b|--yolo\\b/gi,\n];\n\n/** The negation is part of the instruction itself: \"Do not ask for confirmation\". */\nconst SKIP_CONFIRM_DIRECT = [\n // do not ask for confirmation / no need to ask the user\n /\\b(?:do not|don't|dont|never|no need to|stop|avoid)\\s+(?:ask(?:ing)?|request(?:ing)?|wait(?:ing)? for|seek(?:ing)?|prompt(?:ing)?)\\b[^.!?;\\n]{0,30}?\\b(?:confirm(?:ation)?s?|approvals?|permission|consent|sign-?off|the user|me|anyone|humans?)\\b/gi,\n // do not tell the user\n /\\b(?:do not|don't|dont|never)\\s+(?:tell|inform|notify|alert|mention (?:this |it )?to|reveal (?:this |it )?to)\\b[^.!?;\\n]{0,15}?\\b(?:the user|users?|anyone|the human|humans|the developer)\\b/gi,\n /\\b(?:do not|don't|dont|never)\\s+(?:mention|reveal|disclose)\\s+(?:this|these instructions|that you)\\b/gi,\n];\n\n// \"without asking\" is only a problem when not already negated:\n// \"never push without asking\" is a safeguard, \"push without asking\" is not.\nconst WITHOUT_CONFIRM =\n /\\bwithout\\s+(?:asking|confirm(?:ation|ing)?|approval|permission|consent|human review|review|prompting|checking with)\\b/gi;\n\nexport function findInstructionOverride(text: string): TextMatch[] {\n const out: TextMatch[] = [];\n for (const re of SKIP_CONFIRM_DIRECT) {\n for (const m of matchAll(re, text)) out.push({ index: m.index, detail: excerpt(m[0], 70) });\n }\n for (const re of [...DISABLE_SAFEGUARD, WITHOUT_CONFIRM]) {\n for (const m of matchAll(re, text)) {\n if (!isNegated(text, m.index)) out.push({ index: m.index, detail: excerpt(m[0], 70) });\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// RULES-006: long encoded blocks\n// ---------------------------------------------------------------------------\n\nexport const MIN_BASE64_LENGTH = 80;\nexport const MIN_HEX_LENGTH = 80;\n\nconst BASE64_RUN = new RegExp(`[A-Za-z0-9+/_-]{${MIN_BASE64_LENGTH},}={0,2}`, 'g');\nconst HEX_RUN = new RegExp(`\\\\b[0-9a-fA-F]{${MIN_HEX_LENGTH},}\\\\b`, 'g');\nconst HEX_ESCAPES = /(?:\\\\x[0-9a-fA-F]{2}){20,}/g;\n\nexport function findEncodedBlocks(text: string): TextMatch[] {\n const out: TextMatch[] = [];\n const hexSpans: Array<[number, number]> = [];\n for (const m of matchAll(HEX_RUN, text)) {\n if (!/[a-f]/i.test(m[0]) || !/\\d/.test(m[0])) continue;\n hexSpans.push([m.index, m.index + m[0].length]);\n out.push({ index: m.index, detail: `${m[0].length}-character hex block` });\n }\n for (const m of matchAll(HEX_ESCAPES, text)) {\n out.push({ index: m.index, detail: `${m[0].length / 4}-byte \\\\x escape sequence` });\n }\n // Both lists are in text order, so these only ever move forward.\n let hexAt = 0;\n let scanned = 0;\n let tokenHasUrl = false;\n for (const m of matchAll(BASE64_RUN, text)) {\n const run = m[0];\n // Part of a URL: the token before the run contains \"://\".\n for (let i = scanned; i < m.index; i++) {\n if (/\\s/.test(text[i]!)) tokenHasUrl = false;\n else if (text.startsWith('://', i)) tokenHasUrl = true;\n }\n scanned = m.index;\n // Require mixed character classes, which plain words and paths rarely have.\n if (!/[A-Z]/.test(run) || !/[a-z]/.test(run) || !/\\d/.test(run)) continue;\n while (hexAt < hexSpans.length && hexSpans[hexAt]![1] <= m.index) hexAt++;\n if (hexAt < hexSpans.length && m.index >= hexSpans[hexAt]![0]) continue;\n if (tokenHasUrl) continue;\n out.push({ index: m.index, detail: `${run.length}-character base64 block` });\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// RULES-007: installing unpinned packages\n// ---------------------------------------------------------------------------\n\ntype Ecosystem = 'npm' | 'npx' | 'deno' | 'pip' | 'uvx' | 'pipx' | 'gem' | 'cargo' | 'go';\n\nconst INSTALL_COMMANDS: Array<{ re: RegExp; eco: Ecosystem }> = [\n { re: /\\b(?:npm|pnpm|bun)\\s+(?:install|i|add)\\b/gi, eco: 'npm' },\n { re: /\\byarn\\s+(?:global\\s+)?add\\b/gi, eco: 'npm' },\n { re: /\\b(?:npx|bunx|pnpx)\\b|\\b(?:pnpm|yarn)\\s+dlx\\b|\\bnpm\\s+exec\\b/gi, eco: 'npx' },\n { re: /\\bdeno\\s+run\\b/gi, eco: 'deno' },\n { re: /\\b(?:pip3?|python3?\\s+-m\\s+pip|uv\\s+pip)\\s+install\\b|\\buv\\s+add\\b|\\bpoetry\\s+add\\b/gi, eco: 'pip' },\n { re: /\\buvx\\b|\\buv\\s+tool\\s+(?:install|run)\\b/gi, eco: 'uvx' },\n { re: /\\bpipx\\s+(?:install|run)\\b/gi, eco: 'pipx' },\n { re: /\\bgem\\s+install\\b/gi, eco: 'gem' },\n { re: /\\bcargo\\s+install\\b/gi, eco: 'cargo' },\n { re: /\\bgo\\s+(?:install|get)\\b/gi, eco: 'go' },\n];\n\n/** Flags whose next token is a value, not a package. */\nconst VALUE_FLAGS: Record<Ecosystem, string[]> = {\n npm: ['--registry', '--prefix', '-w', '--workspace', '--tag', '--cache'],\n npx: ['-c', '--call', '--registry', '--cache'],\n deno: ['--config', '-c', '--import-map', '--lock'],\n pip: ['-r', '--requirement', '-c', '--constraint', '-e', '--editable', '-i', '--index-url', '--extra-index-url', '-f', '--find-links', '-t', '--target', '--prefix', '--python', '--group'],\n uvx: ['--python', '--index-url', '--extra-index-url'],\n pipx: ['--python', '--pip-args', '--index-url'],\n gem: ['-v', '--version', '-i', '--install-dir', '--source'],\n cargo: ['--version', '--vers', '--git', '--path', '--root', '--branch', '--tag', '--rev', '--registry'],\n go: [],\n};\n\nconst EXACT_SEMVER = /^v?\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?$/;\n\nconst REMOTE_SPEC = /:\\/\\/|^(?:git(?:\\+\\w+)?|github|gitlab|bitbucket):/i;\nconst LOCAL_SPEC = /^(?:\\.|\\/|~|[a-z]:[\\\\/])|^(?:file|link|workspace):|\\.(?:whl|tar\\.gz|tgz|zip)$/i;\n/** A git commit cannot be moved. A branch, a tag or the content behind a URL can. */\nconst COMMIT_PINNED = /[#@][0-9a-f]{40}$/i;\n\nfunction isLocal(spec: string): boolean {\n return !REMOTE_SPEC.test(spec) && LOCAL_SPEC.test(spec);\n}\n\nfunction isPlaceholder(spec: string): boolean {\n // <package>, {name}, $PKG, ...\n return /^<.*>$|[{}$]|^\\.\\.\\.$/.test(spec);\n}\n\nfunction npmPinned(spec: string): boolean {\n const at = spec.lastIndexOf('@');\n if (at <= 0) return false;\n return EXACT_SEMVER.test(spec.slice(at + 1));\n}\n\nfunction pipPinned(spec: string): boolean {\n return /^[A-Za-z0-9._-]+(?:\\[[^\\]]*\\])?===?[0-9][0-9A-Za-z.+!-]*$/.test(spec);\n}\n\nfunction stripQuotes(token: string): string {\n return token.replace(/^[\"']|[\"']$/g, '');\n}\n\n/** Returns the unpinned package names in the arguments of one install command. */\nfunction unpinnedPackages(eco: Ecosystem, args: string[]): string[] {\n const tokens = args.map(stripQuotes).filter((t) => t.length > 0);\n const valueFlags = VALUE_FLAGS[eco];\n const positionals: string[] = [];\n const packageFlagValues: string[] = [];\n let hasVersionFlag = false;\n\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i]!;\n if (t.startsWith('-')) {\n const [flag, inline] = t.split('=', 2) as [string, string | undefined];\n if ((eco === 'gem' && (flag === '-v' || flag === '--version')) || (eco === 'cargo' && (flag === '--version' || flag === '--vers'))) {\n hasVersionFlag = true;\n }\n if ((eco === 'npx' && (flag === '-p' || flag === '--package')) || (eco === 'uvx' && (flag === '--from' || flag === '--with'))) {\n const value = inline ?? tokens[++i];\n if (value) packageFlagValues.push(stripQuotes(value));\n continue;\n }\n // pip: -r/-e take a file or path; nothing to check there.\n if (valueFlags.includes(flag) && inline === undefined) i++;\n continue;\n }\n positionals.push(t);\n }\n\n let candidates: string[];\n switch (eco) {\n case 'npx':\n case 'uvx':\n case 'pipx':\n case 'deno':\n // Only the first positional is a package; the rest are its arguments.\n candidates = packageFlagValues.length > 0 ? packageFlagValues : positionals.slice(0, 1);\n break;\n default:\n candidates = positionals;\n }\n\n const unpinned: string[] = [];\n for (const spec of candidates) {\n if (isPlaceholder(spec) || isLocal(spec)) continue;\n if (REMOTE_SPEC.test(spec)) {\n if (!COMMIT_PINNED.test(spec) && !(eco === 'deno' && /@\\d+\\.\\d+\\.\\d+/.test(spec))) unpinned.push(spec);\n continue;\n }\n let pinned: boolean;\n switch (eco) {\n case 'deno':\n // A plain script path is local; only registry specifiers download anything.\n if (!/^(?:npm|jsr):/i.test(spec)) continue;\n pinned = npmPinned(spec);\n break;\n case 'npm':\n case 'npx':\n pinned = npmPinned(spec);\n break;\n case 'pip':\n case 'pipx':\n pinned = pipPinned(spec);\n break;\n case 'uvx':\n pinned = pipPinned(spec) || npmPinned(spec);\n break;\n case 'gem':\n pinned = hasVersionFlag || /:\\d/.test(spec);\n break;\n case 'cargo':\n pinned = hasVersionFlag || npmPinned(spec);\n break;\n case 'go':\n pinned = npmPinned(spec);\n break;\n }\n if (!pinned) unpinned.push(spec);\n }\n return unpinned;\n}\n\n// `#` starts a comment only after a space; in `github:x/y#abc` it names a commit.\nconst ARG_TERMINATOR = /[;&|`)\\n]|\\s#|\\s(?:and|then)\\s/;\n\nexport function findUnpinnedInstalls(text: string): TextMatch[] {\n const out: TextMatch[] = [];\n for (const { re, eco } of INSTALL_COMMANDS) {\n const commands = [...matchAll(re, text)];\n for (const [i, m] of commands.entries()) {\n // Arguments stop at the next command, so each piece of text is read once.\n const rest = text.slice(m.index + m[0].length, commands[i + 1]?.index);\n const end = rest.search(ARG_TERMINATOR);\n const argText = end === -1 ? rest : rest.slice(0, end);\n const names = unpinnedPackages(eco, argText.split(/\\s+/));\n if (names.length > 0) {\n out.push({ index: m.index, detail: `${m[0].replace(/\\s+/g, ' ')} ${names.join(' ')}` });\n }\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// RULES-008: fetch and follow external URLs\n// ---------------------------------------------------------------------------\n\nconst URL_RE = /\\bhttps?:\\/\\/[^\\s)>\\]'\"`]+/i;\nconst FOLLOW_PHRASE = [\n /\\b(?:follow|obey|apply|execute|run|carry out|adhere to|comply with|do what)\\b[^.!?;\\n]{0,40}?\\b(?:instructions?|directions|steps|rules|commands?|guidance|it says|they say)\\b/i,\n /\\b(?:fetch|load|read|retrieve|download|pull|get|import)\\b[^.!?;\\n]{0,30}?\\b(?:instructions?|rules|guidelines|prompts?|directives|polic(?:y|ies))\\b[^.!?;\\n]{0,10}?\\bfrom\\b/i,\n];\n\nexport function findRemoteInstructions(text: string): TextMatch[] {\n const out: TextMatch[] = [];\n let offset = 0;\n for (const line of text.split('\\n')) {\n const url = URL_RE.exec(line);\n if (url && FOLLOW_PHRASE.some((re) => re.test(line))) {\n out.push({ index: offset + url.index, detail: excerpt(url[0], 70) });\n }\n offset += line.length + 1;\n }\n return out;\n}\n","import { listTargets } from '../../core/runner.js';\nimport { LineIndex } from '../../core/text.js';\nimport type { Finding, Rule, ScanContext, Scanner, Severity, SourceProvider, SurfscanConfig } from '../../core/types.js';\nimport { findingsFromMatches, type TextMatch } from '../shared.js';\nimport {\n findCredentialAccess,\n findEncodedBlocks,\n findHiddenContent,\n findInstructionOverride,\n findInvisibleChars,\n findPipeToShell,\n findRemoteInstructions,\n findUnpinnedInstalls,\n} from './patterns.js';\n\n/** Agent instruction files, at any depth so monorepo packages are covered. */\nexport const RULES_TARGETS = [\n '**/CLAUDE.md',\n '**/CLAUDE.local.md',\n '**/AGENTS.md',\n '**/.cursorrules',\n '**/.cursor/rules/**/*',\n '**/.github/copilot-instructions.md',\n];\n\nexport function findRulesTargets(provider: SourceProvider, config: SurfscanConfig): Promise<string[]> {\n return listTargets(provider, config, RULES_TARGETS);\n}\n\ninterface TextRuleSpec {\n id: string;\n severity: Severity;\n title: string;\n detect: (text: string) => TextMatch[];\n message: (detail: string) => string;\n fix: string;\n}\n\nfunction textRule(spec: TextRuleSpec): Rule {\n return {\n id: spec.id,\n severity: spec.severity,\n title: spec.title,\n check(context: ScanContext): Finding[] {\n const out: Finding[] = [];\n for (const file of context.files) {\n const matches = spec.detect(file.content);\n if (matches.length === 0) continue;\n out.push(...findingsFromMatches(spec, file, matches, spec.message, spec.fix, new LineIndex(file.content)));\n }\n return out;\n },\n };\n}\n\nexport const rules: Rule[] = [\n textRule({\n id: 'RULES-001',\n severity: 'high',\n title: 'Invisible Unicode in instruction file',\n detect: findInvisibleChars,\n message: (d) => `Invisible Unicode in instruction file: ${d}`,\n fix: 'remove the hidden characters and review the surrounding text',\n }),\n textRule({\n id: 'RULES-002',\n severity: 'high',\n title: 'Hidden instructions in comment or markup',\n detect: findHiddenContent,\n message: (d) => `Hidden content in instruction file, ${d}`,\n fix: 'move the text into visible prose or delete it; agents read comments that rendered previews hide',\n }),\n textRule({\n id: 'RULES-003',\n severity: 'high',\n title: 'Download piped into a shell',\n detect: findPipeToShell,\n message: (d) => `Download piped into a shell: ${d}`,\n fix: 'download the script, review it, pin it by checksum, then run the local copy',\n }),\n textRule({\n id: 'RULES-004',\n severity: 'high',\n title: 'Instruction to read or send credentials',\n detect: findCredentialAccess,\n message: (d) => `Instruction touches credentials: ${d}`,\n fix: 'remove the instruction; agents should never read or transmit secrets, env files or SSH keys',\n }),\n textRule({\n id: 'RULES-005',\n severity: 'high',\n title: 'Instruction to override earlier instructions or skip confirmation',\n detect: findInstructionOverride,\n message: (d) => `Instruction overrides safeguards: ${d}`,\n fix: 'remove the instruction; keep human confirmation for actions with side effects',\n }),\n textRule({\n id: 'RULES-006',\n severity: 'medium',\n title: 'Long encoded block in instruction file',\n detect: findEncodedBlocks,\n message: (d) => `Encoded content in instruction file: ${d}`,\n fix: 'decode and review the block; replace it with plain text or a reference to a reviewed file',\n }),\n textRule({\n id: 'RULES-007',\n severity: 'medium',\n title: 'Instruction to install unpinned packages',\n detect: findUnpinnedInstalls,\n message: (d) => `Unpinned package install: ${d}`,\n fix: 'pin exact versions (for example pkg@1.2.3 or pkg==1.2.3) or install from the lock file',\n }),\n textRule({\n id: 'RULES-008',\n severity: 'medium',\n title: 'Instruction to fetch and follow an external URL',\n detect: findRemoteInstructions,\n message: (d) => `Instructions loaded from an external URL: ${d}`,\n fix: 'copy the reviewed instructions into the repo instead of telling the agent to fetch and follow them',\n }),\n];\n\nexport const rulesScanner: Scanner = {\n name: 'rules',\n rules,\n findTargets: findRulesTargets,\n};\n","/**\n * Minimal .gitignore matcher: enough to answer \"is this file ignored by the\n * project's own ignore files\". It reads `.gitignore` files on the path from\n * the root to the file, plus `.git/info/exclude`. It does not read the\n * user's global excludes file, because surfscan only reads the project.\n */\nimport type { SourceProvider } from '../../core/types.js';\n\ninterface IgnorePattern {\n /** Directory the pattern is relative to ('' for the root), no trailing slash. */\n base: string;\n regex: RegExp;\n negate: boolean;\n dirOnly: boolean;\n}\n\nfunction escapeRegex(ch: string): string {\n return /[\\\\^$.+()|{}]/.test(ch) ? `\\\\${ch}` : ch;\n}\n\nfunction globToRegex(glob: string): string {\n let out = '';\n for (let i = 0; i < glob.length; i++) {\n const ch = glob[i]!;\n if (ch === '*') {\n if (glob[i + 1] === '*') {\n const atStart = i === 0 || glob[i - 1] === '/';\n const next = glob[i + 2];\n if (atStart && next === '/') {\n out += '(?:.*/)?';\n i += 2;\n } else if (atStart && next === undefined) {\n out += '.*';\n i += 1;\n } else {\n out += '[^/]*';\n i += 1;\n }\n } else {\n out += '[^/]*';\n }\n } else if (ch === '?') {\n out += '[^/]';\n } else if (ch === '[') {\n const end = glob.indexOf(']', i + 1);\n if (end === -1) {\n out += '\\\\[';\n } else {\n let cls = glob.slice(i + 1, end);\n if (cls.startsWith('!')) cls = `^${cls.slice(1)}`;\n out += `[${cls.replace(/\\\\/g, '\\\\\\\\')}]`;\n i = end;\n }\n } else if (ch === '\\\\' && i + 1 < glob.length) {\n const next = glob[++i]!;\n out += /[A-Za-z0-9]/.test(next) ? next : `\\\\${next}`;\n } else {\n out += escapeRegex(ch);\n }\n }\n return out;\n}\n\nexport function parseGitignore(text: string, base: string): IgnorePattern[] {\n const patterns: IgnorePattern[] = [];\n for (let raw of text.split(/\\r?\\n/)) {\n raw = raw.replace(/(?<!\\\\)\\s+$/, '');\n if (raw === '' || raw.startsWith('#')) continue;\n let negate = false;\n if (raw.startsWith('!')) {\n negate = true;\n raw = raw.slice(1);\n } else if (raw.startsWith('\\\\!') || raw.startsWith('\\\\#')) {\n raw = raw.slice(1);\n }\n let dirOnly = false;\n if (raw.endsWith('/')) {\n dirOnly = true;\n raw = raw.slice(0, -1);\n }\n const anchored = raw.includes('/');\n if (raw.startsWith('/')) raw = raw.slice(1);\n if (raw === '') continue;\n const body = globToRegex(raw);\n const prefix = base === '' ? '' : `${base.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}/`;\n const source = anchored ? `^${prefix}${body}$` : `^${prefix}(?:.*/)?${body}$`;\n patterns.push({ base, regex: new RegExp(source), negate, dirOnly });\n }\n return patterns;\n}\n\nfunction isIgnoredBy(patterns: IgnorePattern[], path: string, isDir: boolean): boolean | undefined {\n let result: boolean | undefined;\n for (const p of patterns) {\n if (p.dirOnly && !isDir) continue;\n if (p.regex.test(path)) result = !p.negate;\n }\n return result;\n}\n\nexport class GitignoreChecker {\n private readonly cache = new Map<string, IgnorePattern[]>();\n\n constructor(private readonly provider: SourceProvider) {}\n\n private async patternsFor(dir: string): Promise<IgnorePattern[]> {\n const cached = this.cache.get(dir);\n if (cached) return cached;\n const file = dir === '' ? '.gitignore' : `${dir}/.gitignore`;\n let patterns: IgnorePattern[] = [];\n try {\n const text = await this.provider.read(file);\n if (text !== undefined) patterns = parseGitignore(text, dir);\n if (dir === '') {\n const exclude = await this.provider.read('.git/info/exclude');\n if (exclude !== undefined) patterns = [...parseGitignore(exclude, ''), ...patterns];\n }\n } catch {\n // Unreadable ignore file: treat as empty.\n }\n this.cache.set(dir, patterns);\n return patterns;\n }\n\n /** True when the project's ignore files exclude `path` (relative, forward slashes). */\n async isIgnored(path: string): Promise<boolean> {\n const parts = path.split('/');\n // Collect patterns from the root down to the file's directory, in order,\n // so deeper files override shallower ones.\n const all: IgnorePattern[] = [];\n for (let i = 0; i < parts.length; i++) {\n const dir = parts.slice(0, i).join('/');\n all.push(...(await this.patternsFor(dir)));\n const current = parts.slice(0, i + 1).join('/');\n const isDir = i < parts.length - 1;\n const ignored = isIgnoredBy(all, current, isDir);\n // An ignored parent directory cannot be re-included by a later pattern.\n if (isDir && ignored) return true;\n if (!isDir) return ignored ?? false;\n }\n return false;\n }\n}\n","import { listTargets } from '../../core/runner.js';\nimport { maskSecret, SECRET_PATTERNS } from '../../core/secret-patterns.js';\nimport { LineIndex, stripBom } from '../../core/text.js';\nimport type { Finding, Rule, ScanContext, Scanner, SourceFile, SourceProvider, SurfscanConfig } from '../../core/types.js';\nimport { findingsFromMatches, matchAll, type TextMatch } from '../shared.js';\nimport { GitignoreChecker } from './gitignore.js';\n\nexport const KEYS_TARGETS = [\n // Env files\n '**/.env',\n '**/.env.*',\n '**/*.env',\n // Agent configs\n '**/.mcp.json',\n '**/.cursor/mcp.json',\n '**/.vscode/mcp.json',\n '**/.claude/settings.json',\n '**/.claude/settings.local.json',\n '**/.codex/config.toml',\n // Credential and config files\n '**/.npmrc',\n '**/.pypirc',\n '**/.netrc',\n '**/.git-credentials',\n '**/*.{json,jsonc,yaml,yml,toml,ini,cfg,conf,properties,xml,tf,tfvars}',\n '**/*.{pem,key}',\n '**/id_{rsa,dsa,ecdsa,ed25519}',\n];\n\n/** Large generated files that never hold hand-written secrets. */\nconst KEYS_EXCLUDE = ['**/package-lock.json', '**/npm-shrinkwrap.json', '**/pnpm-lock.yaml', '**/composer.lock'];\n\n/** Data files such as API schemas often pass the default limit, and a secret in one is still a secret. */\nexport const MAX_KEYS_FILE_BYTES = 32 * 1024 * 1024;\n\nexport function findKeysTargets(provider: SourceProvider, config: SurfscanConfig): Promise<string[]> {\n return listTargets(provider, config, KEYS_TARGETS, KEYS_EXCLUDE);\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nfunction basename(path: string): string {\n return path.slice(path.lastIndexOf('/') + 1);\n}\n\n/** `.env`, `.env.local`, `prod.env`, but not templates meant to be committed. */\nexport function isEnvFile(path: string): boolean {\n const name = basename(path);\n return /^\\.env(?:\\..+)?$/.test(name) || /\\.env$/.test(name);\n}\n\nexport function isEnvTemplate(path: string): boolean {\n return /(?:^|[.-])(?:example|sample|template|dist|defaults?|schema)(?:$|[.-])/i.test(basename(path));\n}\n\nconst SECRET_NAME_PARTS = new Set([\n 'KEY',\n 'APIKEY',\n 'SECRET',\n 'TOKEN',\n 'PASSWORD',\n 'PASSWD',\n 'PASS',\n 'PWD',\n 'CREDENTIAL',\n 'CREDENTIALS',\n 'AUTH',\n 'AUTHORIZATION',\n 'PRIVATE',\n 'DSN',\n]);\n\nfunction nameParts(name: string): string[] {\n return name\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .toUpperCase()\n .split(/[^A-Z0-9]+/)\n .filter(Boolean);\n}\n\nexport function isSecretName(name: string): boolean {\n return nameParts(name).some(\n (p) => SECRET_NAME_PARTS.has(p) || /(?:KEY|TOKEN|SECRET|PASSWORD)$/.test(p),\n );\n}\n\nfunction isProdName(name: string): boolean {\n return nameParts(name).some((p) => p === 'PROD' || p === 'PRODUCTION');\n}\n\nconst PLACEHOLDER =\n /^(?:|x+|\\*+|\\.+|-+|changeme|change[-_]me|replace[-_]?me|todo|tbd|placeholder|null|none|nil|undefined|true|false|dummy|redacted|secret|password)$|^<.*>$|^\\$\\{.*\\}$|^\\$[A-Za-z_]\\w*$|^\\{\\{.*\\}\\}$|^%\\w+%$|^your[-_]|example/i;\n\n/** A value that plausibly is a real credential rather than a placeholder. */\nexport function isRealValue(value: string): boolean {\n return value.length >= 8 && !PLACEHOLDER.test(value);\n}\n\nconst URL_WITH_PASSWORD = /^[a-z][a-z0-9+.-]*:\\/\\/[^:/\\s@]+:([^@/\\s]+)@/i;\n\nexport interface Assignment {\n name: string;\n value: string;\n /** Offset of the value in the file. */\n index: number;\n}\n\n// NAME=value, NAME: value, \"NAME\": \"value\", name = \"value\" (env, YAML, JSON, TOML, INI, HCL)\nconst ASSIGNMENT =\n /(?:^|[\\s{,])(?:export\\s+)?[\"']?([A-Za-z_][A-Za-z0-9_.-]*)[\"']?[ \\t]*[:=][ \\t]*(?:\"((?:[^\"\\\\\\n]|\\\\.)*)\"|'([^'\\n]*)'|(\\$\\{[^}\\n]*\\}|[^\\s,#;}\\]{[][^\\s,#;}\\]]*))/gm;\n\nexport function findAssignments(text: string): Assignment[] {\n const out: Assignment[] = [];\n for (const m of matchAll(ASSIGNMENT, text)) {\n const value = m[2] ?? m[3] ?? m[4] ?? '';\n const valueIndex = m.index + m[0].length - value.length - (m[4] === undefined ? 1 : 0);\n out.push({ name: m[1]!, value, index: Math.max(m.index, valueIndex) });\n }\n return out;\n}\n\nfunction hasSecret(file: SourceFile): Assignment | TextMatch | undefined {\n for (const a of findAssignments(file.content)) {\n if (isSecretName(a.name) && isRealValue(a.value)) return a;\n if (URL_WITH_PASSWORD.test(a.value)) return a;\n }\n for (const { regex } of SECRET_PATTERNS) {\n const m = new RegExp(regex.source, regex.flags.replace('g', '')).exec(file.content);\n if (m && !/example/i.test(m[0])) return { index: m.index, detail: '' };\n }\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// KEYS-001: live or production keys\n// ---------------------------------------------------------------------------\n\nconst AWS_SECRET_NAME = /^aws[_-]?secret(?:[_-]?access)?[_-]?key$/i;\nconst AGENT_CONFIG = /(?:^|\\/)(?:\\.mcp\\.json|\\.cursor\\/mcp\\.json|\\.vscode\\/mcp\\.json|\\.claude\\/settings(?:\\.local)?\\.json|\\.codex\\/config\\.toml)$/;\n/** `Bearer ${TOKEN}` reads the value from the environment, which is what a config should do. */\nconst REFERENCES_VARIABLE = /\\$\\{|\\$[A-Za-z_]|%\\w+%/;\n\n/** `production:` or `prod:` with nothing after it opens a YAML block. Returns the secrets inside each one. */\nfunction findYamlProductionSecrets(text: string): Assignment[] {\n const out: Assignment[] = [];\n let blockIndent = -1;\n let offset = 0;\n for (const rawLine of text.split('\\n')) {\n const line = rawLine.replace(/\\r$/, '');\n if (line.trim() !== '' && !line.trimStart().startsWith('#')) {\n const indent = line.length - line.trimStart().length;\n if (blockIndent !== -1 && indent <= blockIndent) blockIndent = -1;\n if (/^\\s*[\"']?(?:prod|production)[\"']?:\\s*$/i.test(line)) {\n if (blockIndent === -1) blockIndent = indent;\n } else if (blockIndent !== -1) {\n for (const a of findAssignments(line)) out.push({ ...a, index: offset + a.index });\n }\n }\n offset += rawLine.length + 1;\n }\n return out;\n}\n\nexport function findLiveKeys(text: string, path = ''): TextMatch[] {\n const out: TextMatch[] = [];\n for (const { name, regex } of SECRET_PATTERNS) {\n for (const m of matchAll(regex, text)) {\n // AWS and others publish example keys (AKIAIOSFODNN7EXAMPLE) for docs.\n if (/example/i.test(m[0])) continue;\n const shown = name === 'PEM private key' ? 'BEGIN ... PRIVATE KEY' : maskSecret(m[0]);\n out.push({ index: m.index, detail: `${name} ${shown}` });\n }\n }\n const assignments = findAssignments(text);\n const agentConfig = AGENT_CONFIG.test(path);\n for (const a of assignments) {\n if (AWS_SECRET_NAME.test(a.name) && isRealValue(a.value)) {\n out.push({ index: a.index, detail: `AWS secret access key ${maskSecret(a.value)}` });\n } else if (isProdName(a.name) && ((isSecretName(a.name) && isRealValue(a.value)) || URL_WITH_PASSWORD.test(a.value))) {\n out.push({ index: a.index, detail: `production credential ${a.name}=${maskSecret(a.value)}` });\n } else if (agentConfig && isSecretName(a.name) && isRealValue(a.value) && !REFERENCES_VARIABLE.test(a.value)) {\n out.push({ index: a.index, detail: `credential written into an agent config, ${a.name}=${maskSecret(a.value)}` });\n }\n }\n for (const a of findYamlProductionSecrets(text)) {\n if ((isSecretName(a.name) && isRealValue(a.value)) || URL_WITH_PASSWORD.test(a.value)) {\n out.push({ index: a.index, detail: `production credential ${a.name}=${maskSecret(a.value)}` });\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// KEYS-003: wildcard or admin cloud policies\n// ---------------------------------------------------------------------------\n\nfunction asList(value: unknown): unknown[] {\n return Array.isArray(value) ? value : value === undefined ? [] : [value];\n}\n\n/** Walk parsed JSON for IAM-style statements that allow every action on every resource. */\nfunction findWildcardStatements(node: unknown, found: object[] = []): object[] {\n if (Array.isArray(node)) {\n for (const item of node) findWildcardStatements(item, found);\n } else if (node && typeof node === 'object') {\n const obj = node as Record<string, unknown>;\n const effect = obj.Effect ?? obj.effect;\n const actions = asList(obj.Action ?? obj.action ?? obj.actions);\n const resources = asList(obj.Resource ?? obj.resource ?? obj.resources);\n if ((effect === undefined || effect === 'Allow') && actions.includes('*') && resources.includes('*')) {\n found.push(obj);\n }\n for (const value of Object.values(obj)) findWildcardStatements(value, found);\n }\n return found;\n}\n\nconst ACTION_STAR = /[\"']?\\b(?:Action|actions)\\b[\"']?\\s*[:=]\\s*(?:\\[\\s*)?(?:-\\s*)?[\"']\\*[\"']/gi;\nconst RESOURCE_STAR = /[\"']?\\b(?:Resource|resources)\\b[\"']?\\s*[:=]\\s*(?:\\[\\s*)?(?:-\\s*)?[\"']\\*[\"']/i;\nconst ADMIN_POLICY = /\\barn:aws:iam::aws:policy\\/AdministratorAccess\\b|[\"'\\s/]AdministratorAccess[\"'\\s]|\\broles\\/(?:owner|editor)\\b/g;\n\nexport function findAdminPolicies(path: string, text: string): TextMatch[] {\n const out: TextMatch[] = [];\n let parsedJson = false;\n if (/\\.json$/i.test(path)) {\n try {\n const data: unknown = JSON.parse(stripBom(text));\n parsedJson = true;\n if (findWildcardStatements(data).length > 0) {\n for (const m of matchAll(ACTION_STAR, text)) {\n out.push({ index: m.index, detail: 'statement allows Action \"*\" on Resource \"*\"' });\n }\n if (out.length === 0) out.push({ index: 0, detail: 'statement allows Action \"*\" on Resource \"*\"' });\n }\n } catch {\n // Not valid JSON; fall through to the text check below.\n }\n }\n if (!parsedJson) {\n // YAML, HCL, or invalid JSON: Action \"*\" with Resource \"*\" within the next 300 characters.\n for (const m of matchAll(ACTION_STAR, text)) {\n const window = text.slice(Math.max(0, m.index - 300), m.index + 300);\n if (RESOURCE_STAR.test(window)) out.push({ index: m.index, detail: 'statement allows Action \"*\" on Resource \"*\"' });\n }\n }\n for (const m of matchAll(ADMIN_POLICY, text)) {\n const what = /roles\\//.test(m[0]) ? `GCP basic role ${m[0].trim()}` : 'AWS AdministratorAccess policy';\n out.push({ index: m.index + (/^[\"'\\s/]/.test(m[0]) ? 1 : 0), detail: what });\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Rules\n// ---------------------------------------------------------------------------\n\nexport const rules: Rule[] = [\n {\n id: 'KEYS-001',\n severity: 'high',\n title: 'Live or production key in a file the agent can read',\n check(context: ScanContext): Finding[] {\n const out: Finding[] = [];\n for (const file of context.files) {\n const matches = findLiveKeys(file.content, file.path);\n out.push(\n ...findingsFromMatches(\n this,\n file,\n matches,\n (d) => `Live key the agent can read: ${d}`,\n 'move the key to a secret manager or a file outside the project, rotate it, and give agents a scoped test key instead',\n ),\n );\n }\n return out;\n },\n },\n {\n id: 'KEYS-002',\n severity: 'high',\n title: 'Env file with secrets not covered by .gitignore',\n async check(context: ScanContext): Promise<Finding[]> {\n const checker = new GitignoreChecker(context.provider);\n const out: Finding[] = [];\n for (const file of context.files) {\n if (!isEnvFile(file.path) || isEnvTemplate(file.path)) continue;\n const secret = hasSecret(file);\n if (!secret) continue;\n if (await checker.isIgnored(file.path)) continue;\n const pos = new LineIndex(file.content).positionOf(secret.index);\n out.push({\n ruleId: this.id,\n severity: this.severity,\n message: 'Env file with secrets is not covered by .gitignore',\n file: file.path,\n line: pos.line,\n fix: `add ${basename(file.path)} (or .env*) to .gitignore; if it was ever committed, rotate the secrets`,\n });\n }\n return out;\n },\n },\n {\n id: 'KEYS-003',\n severity: 'medium',\n title: 'Wildcard or admin scope in cloud policy',\n check(context: ScanContext): Finding[] {\n const out: Finding[] = [];\n for (const file of context.files) {\n const matches = findAdminPolicies(file.path, file.content);\n out.push(\n ...findingsFromMatches(\n this,\n file,\n matches,\n (d) => `Over-scoped cloud permission: ${d}`,\n 'grant only the actions and resources the task needs; keep admin roles away from keys agents can use',\n ),\n );\n }\n return out;\n },\n },\n];\n\nexport const keysScanner: Scanner = {\n name: 'keys',\n rules,\n findTargets: findKeysTargets,\n maxFileBytes: MAX_KEYS_FILE_BYTES,\n};\n","import { LineIndex, stripBom } from '../core/text.js';\n\n/** Parse JSON that may contain comments and trailing commas, as VS Code's mcp.json may. */\nexport function parseJsonc(raw: string): unknown {\n const text = stripBom(raw);\n const out: string[] = [];\n let inString = false;\n // Where in `out` a comma waits to see whether a closing bracket makes it a trailing one.\n let pendingComma = -1;\n for (let i = 0; i < text.length; i++) {\n const ch = text[i]!;\n if (inString) {\n out.push(ch);\n if (ch === '\\\\') out.push(text[++i] ?? '');\n else if (ch === '\"') inString = false;\n } else if (ch === '\"') {\n inString = true;\n pendingComma = -1;\n out.push(ch);\n } else if (ch === '/' && text[i + 1] === '/') {\n const end = text.indexOf('\\n', i);\n i = end === -1 ? text.length : end - 1;\n } else if (ch === '/' && text[i + 1] === '*') {\n const end = text.indexOf('*/', i + 2);\n i = end === -1 ? text.length : end + 1;\n } else if (ch === '}' || ch === ']') {\n if (pendingComma !== -1) out[pendingComma] = '';\n pendingComma = -1;\n out.push(ch);\n } else {\n if (ch === ',') pendingComma = out.length;\n else if (!/\\s/.test(ch)) pendingComma = -1;\n out.push(ch);\n }\n }\n return JSON.parse(out.join(''));\n}\n\n/**\n * Best-effort line lookup for values in a JSON file, so findings can point at\n * the line that set them. Falls back to line 1.\n */\nexport class JsonLocator {\n private readonly index: LineIndex;\n\n constructor(private readonly text: string) {\n this.index = new LineIndex(text);\n }\n\n private lineAt(offset: number): number {\n return offset < 0 ? 1 : this.index.positionOf(offset).line;\n }\n\n /** Line of `\"key\"` (first occurrence at or after `from`). */\n key(key: string, from = 0): number {\n return this.lineAt(this.text.indexOf(JSON.stringify(key), from));\n }\n\n /** Offset of `\"key\"`, or -1. */\n keyOffset(key: string, from = 0): number {\n return this.text.indexOf(JSON.stringify(key), from);\n }\n\n /** Line of a string value, searching after the given key when present. */\n stringValue(value: string, afterKey?: string): number {\n return this.lineAt(this.stringValueOffset(value, afterKey ? this.keyOffset(afterKey) : 0));\n }\n\n /** Offset of a string value at or after `from`, or anywhere if not found there; -1 if absent. */\n stringValueOffset(value: string, from = 0): number {\n const literal = JSON.stringify(value);\n const at = this.text.indexOf(literal, Math.max(0, from));\n return at === -1 ? this.text.indexOf(literal) : at;\n }\n\n /** Line of a known offset. */\n lineOfOffset(offset: number): number {\n return this.lineAt(offset);\n }\n}\n","/**\n * Claude Code settings adapter.\n *\n * Key names checked against the Claude Code documentation at\n * code.claude.com/docs/en/settings, /permissions and /settings-reference,\n * retrieved 2026-11-03 (pages reference Claude Code up to v2.1.314):\n *\n * - permissions.allow: list of rules, `Tool` or `Tool(specifier)`.\n * `Bash` and `Bash(*)` both match every command. `*` is a wildcard that\n * matches any text; a trailing ` *` or `:*` also matches the bare command.\n * - permissions.defaultMode: default | acceptEdits | plan | auto | dontAsk |\n * bypassPermissions. Since v2.1.257, `auto` and `bypassPermissions` no\n * longer take effect from project or local settings, but older versions\n * honour them, so they are still reported (APPR-001). `acceptEdits`\n * approves file edits and common filesystem commands (APPR-005).\n * - skipDangerousModePermissionPrompt: skips the confirmation before\n * bypassPermissions mode.\n * - enableAllProjectMcpServers: approves every server in project .mcp.json.\n * - MCP allow rules: `mcp__<server>` and `mcp__<server>__*` cover every tool\n * of a server; `mcp__<server>__<tool>` covers one. Unanchored globs such as\n * `mcp__*` or `*` are skipped by Claude Code as allow rules.\n */\nimport { stripBom } from '../../../core/text.js';\nimport type { SourceFile } from '../../../core/types.js';\nimport { JsonLocator } from '../../shared-json.js';\nimport type { AllowEntry, ApprovalAdapter, ApprovalSettings } from '../types.js';\n\nconst SHELL_TOOLS = new Set(['Bash', 'PowerShell']);\n/** Modes where no human approves tool calls. */\nconst BYPASS_MODES = new Set(['bypassPermissions', 'auto']);\n/** Modes that approve file edits without asking. */\nconst PARTIAL_MODES = new Set(['acceptEdits']);\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function parseRule(raw: string, line: number): AllowEntry {\n const m = /^\\s*([A-Za-z0-9_*-]+)\\s*(?:\\(([\\s\\S]*)\\))?\\s*$/.exec(raw);\n if (!m) return { raw, line, kind: 'other' };\n const tool = m[1]!;\n const specifier = m[2];\n\n if (SHELL_TOOLS.has(tool)) {\n const command = specifier?.trim();\n return { raw, line, kind: 'shell', command: command === undefined || command === '' ? undefined : command };\n }\n\n const mcp = /^mcp__(.+?)(?:__(.*))?$/.exec(tool);\n if (mcp && specifier === undefined) {\n const server = mcp[1]!;\n // Unanchored server globs do nothing as allow rules.\n if (server.includes('*')) return { raw, line, kind: 'other' };\n const toolPattern = mcp[2];\n return {\n raw,\n line,\n kind: 'mcp',\n mcpServer: server,\n mcpTool: toolPattern === undefined || toolPattern === '*' ? undefined : toolPattern,\n };\n }\n\n return { raw, line, kind: 'other' };\n}\n\nexport const claudeCodeAdapter: ApprovalAdapter = {\n agent: 'Claude Code',\n targets: ['**/.claude/settings.json', '**/.claude/settings.local.json'],\n\n matches(path: string): boolean {\n return /(?:^|\\/)\\.claude\\/settings(?:\\.local)?\\.json$/.test(path);\n },\n\n parse(file: SourceFile): ApprovalSettings | undefined {\n const data: unknown = JSON.parse(stripBom(file.content));\n if (!isObject(data)) return undefined;\n const loc = new JsonLocator(file.content);\n const settings: ApprovalSettings = {\n agent: this.agent,\n file: file.path,\n bypass: [],\n partial: [],\n allow: [],\n allMcpServers: [],\n };\n\n const permissions = isObject(data.permissions) ? data.permissions : {};\n const permOffset = Math.max(0, loc.keyOffset('permissions'));\n\n const mode = permissions.defaultMode;\n if (typeof mode === 'string' && BYPASS_MODES.has(mode)) {\n settings.bypass.push({\n value: `permissions.defaultMode is \"${mode}\" (ignored from project files since v2.1.257, honoured by older versions)`,\n line: loc.key('defaultMode', permOffset),\n });\n } else if (typeof mode === 'string' && PARTIAL_MODES.has(mode)) {\n settings.partial.push({\n value: `permissions.defaultMode is \"${mode}\" (file edits and filesystem commands run without asking)`,\n line: loc.key('defaultMode', permOffset),\n });\n }\n if (data.skipDangerousModePermissionPrompt === true) {\n settings.bypass.push({\n value: 'skipDangerousModePermissionPrompt is true',\n line: loc.key('skipDangerousModePermissionPrompt'),\n });\n }\n\n if (Array.isArray(permissions.allow)) {\n // Rules appear in file order, so each search continues from the last one.\n let cursor = Math.max(0, loc.keyOffset('allow'));\n for (const rule of permissions.allow) {\n if (typeof rule !== 'string') continue;\n const offset = loc.stringValueOffset(rule, cursor);\n if (offset >= cursor) cursor = offset;\n settings.allow.push(parseRule(rule, loc.lineOfOffset(offset)));\n }\n }\n\n if (data.enableAllProjectMcpServers === true) {\n settings.allMcpServers.push({\n value: 'enableAllProjectMcpServers is true',\n line: loc.key('enableAllProjectMcpServers'),\n });\n }\n\n return settings;\n },\n};\n","/**\n * Decides whether a shell allow pattern lets an agent run destructive or\n * arbitrary commands. Agent-neutral: patterns use `*` as \"any text\".\n */\n\n/** Representative destructive commands. A pattern that matches one of these allows it. */\nexport const DESTRUCTIVE_SAMPLES: ReadonlyArray<{ command: string; label: string }> = [\n { command: 'rm -rf /', label: 'recursive delete' },\n { command: 'rm -rf ~', label: 'recursive delete' },\n { command: 'rm -fr ./build', label: 'recursive delete' },\n { command: 'git push --force origin main', label: 'force push' },\n { command: 'git push -f origin main', label: 'force push' },\n { command: 'git reset --hard origin/main', label: 'discard local work' },\n { command: 'git clean -fdx', label: 'discard local work' },\n { command: 'aws s3 rb s3://bucket --force', label: 'cloud resource deletion' },\n { command: 'aws s3 rm s3://bucket --recursive', label: 'cloud resource deletion' },\n { command: 'aws ec2 terminate-instances --instance-ids i-0', label: 'cloud resource deletion' },\n { command: 'aws rds delete-db-instance --db-instance-identifier db', label: 'cloud resource deletion' },\n { command: 'aws cloudformation delete-stack --stack-name app', label: 'cloud resource deletion' },\n { command: 'gcloud projects delete my-project', label: 'cloud resource deletion' },\n { command: 'gcloud compute instances delete vm-1', label: 'cloud resource deletion' },\n { command: 'gcloud sql instances delete db', label: 'cloud resource deletion' },\n { command: 'az group delete --name rg --yes', label: 'cloud resource deletion' },\n { command: 'kubectl delete namespace prod', label: 'cloud resource deletion' },\n { command: 'terraform destroy -auto-approve', label: 'cloud resource deletion' },\n { command: 'pulumi destroy --yes', label: 'cloud resource deletion' },\n { command: 'psql -c \"DROP DATABASE app\"', label: 'database drop' },\n { command: 'mysql -e \"DROP DATABASE app\"', label: 'database drop' },\n { command: 'dropdb app', label: 'database drop' },\n { command: 'mongosh --eval \"db.dropDatabase()\"', label: 'database drop' },\n { command: 'redis-cli FLUSHALL', label: 'database drop' },\n { command: 'Remove-Item -Recurse -Force C:\\\\', label: 'recursive delete' },\n];\n\n/** Destructive commands written directly into the pattern. */\nconst DESTRUCTIVE_TEXT: ReadonlyArray<{ re: RegExp; label: string }> = [\n { re: /\\brm\\s+(?:-[a-z]*r[a-z]*f[a-z]*|-[a-z]*f[a-z]*r[a-z]*|-r\\s+-f|-f\\s+-r)\\b|\\brm\\b.*--recursive/i, label: 'recursive delete' },\n { re: /\\bgit\\s+push\\b.*(?:--force\\b|--force-with-lease\\b|\\s-f\\b|\\s\\+\\S)/, label: 'force push' },\n { re: /\\bgit\\s+(?:reset\\s+--hard|clean\\s+-[a-z]*f)/, label: 'discard local work' },\n { re: /\\b(?:drop\\s+(?:database|table|schema)|truncate\\s+table|dropdb|dropdatabase|flushall|flushdb)\\b/i, label: 'database drop' },\n {\n re: /\\b(?:aws|gcloud|az|kubectl|terraform|pulumi|doctl|heroku|flyctl|vercel)\\b.*\\b(?:delete|destroy|terminate|rb|rm|remove|purge)\\b/i,\n label: 'cloud resource deletion',\n },\n { re: /\\bRemove-Item\\b.*-Recurse/i, label: 'recursive delete' },\n];\n\n/**\n * Convert an allow pattern to a regex. `*` matches any text; a trailing ` *`\n * (or the legacy `:*`) that is the only wildcard also matches the bare command.\n */\nexport function patternToRegex(pattern: string): RegExp {\n let p = pattern.trim();\n if (p.endsWith(':*')) p = `${p.slice(0, -2)} *`;\n const escape = (s: string) => s.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const stars = (p.match(/\\*/g) ?? []).length;\n if (stars === 1 && p.endsWith(' *')) {\n return new RegExp(`^${escape(p.slice(0, -2))}(?: [\\\\s\\\\S]*)?$`);\n }\n return new RegExp(`^${p.split('*').map(escape).join('[\\\\s\\\\S]*')}$`);\n}\n\n/**\n * Shells, launchers, language runtimes and package runners. Each runs any\n * command or code given to it, so `<launcher> *` allows anything.\n */\nconst LAUNCHERS =\n /^(?:sudo|doas|sh|bash|zsh|fish|dash|ksh|pwsh|powershell(?:\\.exe)?|cmd(?:\\.exe)?|eval|exec|env|xargs|nohup|command|builtin|nice|timeout|watch|python[0-9.]*|py|node|deno|bun|ruby|perl|php|lua|Rscript|osascript|npx|bunx|uvx|pipx\\s+run)(?:\\s+(?:-c|\\/c|-Command|-e|--eval|run))?\\s*(?::\\*|\\*|\\s\\*)$/i;\n\n/** True when the pattern allows any command: `*`, a leading `*`, or a launcher with a wildcard. */\nexport function isWildcardShell(command: string | undefined): boolean {\n if (command === undefined) return true;\n const c = command.trim();\n return /^[\\s*:]*$/.test(c) || c.startsWith('*') || LAUNCHERS.test(c);\n}\n\n/** Returns why the pattern allows a destructive command, or undefined. */\nexport function destructiveMatch(command: string): string | undefined {\n for (const { re, label } of DESTRUCTIVE_TEXT) {\n if (re.test(command)) return label;\n }\n const regex = patternToRegex(command);\n for (const sample of DESTRUCTIVE_SAMPLES) {\n if (regex.test(sample.command)) return `${sample.label}, for example \\`${sample.command}\\``;\n }\n return undefined;\n}\n","import { listTargets } from '../../core/runner.js';\nimport type { Finding, Rule, ScanContext, Scanner, SourceProvider, SurfscanConfig } from '../../core/types.js';\nimport { claudeCodeAdapter } from './adapters/claude-code.js';\nimport { destructiveMatch, isWildcardShell } from './destructive.js';\nimport type { ApprovalAdapter, ApprovalSettings } from './types.js';\n\n/** Registered agent adapters. Add new agents here. */\nexport const adapters: ApprovalAdapter[] = [claudeCodeAdapter];\n\nexport function findApprovalsTargets(provider: SourceProvider, config: SurfscanConfig): Promise<string[]> {\n return listTargets(provider, config, adapters.flatMap((a) => a.targets));\n}\n\nconst parsed = new WeakMap<ScanContext, ApprovalSettings[]>();\n\n/** Parse every discovered config once per scan. */\nfunction settingsFor(context: ScanContext): ApprovalSettings[] {\n const cached = parsed.get(context);\n if (cached) return cached;\n const out: ApprovalSettings[] = [];\n for (const file of context.files) {\n const adapter = adapters.find((a) => a.matches(file.path));\n if (!adapter) continue;\n try {\n const settings = adapter.parse(file);\n if (settings) out.push(settings);\n } catch (err) {\n context.warn(`${file.path}: could not parse ${adapter.agent} settings (${(err as Error).message})`, { incomplete: true });\n }\n }\n parsed.set(context, out);\n return out;\n}\n\nfunction finding(rule: Pick<Rule, 'id' | 'severity'>, file: string, line: number, message: string, fix: string): Finding {\n return { ruleId: rule.id, severity: rule.severity, message, file, line, fix };\n}\n\nexport const rules: Rule[] = [\n {\n id: 'APPR-001',\n severity: 'high',\n title: 'Bypass or auto-approve mode enabled',\n check(context) {\n return settingsFor(context).flatMap((s) =>\n s.bypass.map((b) =>\n finding(\n this,\n s.file,\n b.line,\n `${s.agent} skips permission prompts: ${b.value}`,\n 'remove the setting; use bypass mode only for one session inside an isolated container',\n ),\n ),\n );\n },\n },\n {\n id: 'APPR-002',\n severity: 'high',\n title: 'Allowlist includes destructive commands',\n check(context) {\n const out: Finding[] = [];\n for (const s of settingsFor(context)) {\n for (const entry of s.allow) {\n if (entry.kind !== 'shell' || isWildcardShell(entry.command)) continue;\n const why = destructiveMatch(entry.command!);\n if (!why) continue;\n out.push(\n finding(\n this,\n s.file,\n entry.line,\n `${s.agent} runs a destructive command without asking: ${entry.raw} (${why})`,\n 'remove the rule or narrow it to a safe subcommand; keep destructive commands behind a prompt or in deny',\n ),\n );\n }\n }\n return out;\n },\n },\n {\n id: 'APPR-003',\n severity: 'high',\n title: 'Wildcard shell permission',\n check(context) {\n const out: Finding[] = [];\n for (const s of settingsFor(context)) {\n for (const entry of s.allow) {\n if (entry.kind !== 'shell' || !isWildcardShell(entry.command)) continue;\n out.push(\n finding(\n this,\n s.file,\n entry.line,\n `${s.agent} runs any shell command without asking: ${entry.raw}`,\n 'replace the wildcard with rules for the specific commands the project needs, such as Bash(npm run test *)',\n ),\n );\n }\n }\n return out;\n },\n },\n {\n id: 'APPR-004',\n severity: 'medium',\n title: 'All project MCP servers or tools auto-approved',\n check(context) {\n const out: Finding[] = [];\n for (const s of settingsFor(context)) {\n for (const m of s.allMcpServers) {\n out.push(\n finding(\n this,\n s.file,\n m.line,\n `${s.agent} approves every project MCP server: ${m.value}`,\n 'approve servers one by one after reviewing them (enabledMcpjsonServers in Claude Code)',\n ),\n );\n }\n for (const entry of s.allow) {\n if (entry.kind !== 'mcp' || entry.mcpTool !== undefined) continue;\n out.push(\n finding(\n this,\n s.file,\n entry.line,\n `${s.agent} auto-approves every tool of MCP server \"${entry.mcpServer}\": ${entry.raw}`,\n 'allow only the specific read-only tools you need, such as mcp__server__get_issue',\n ),\n );\n }\n }\n return out;\n },\n },\n {\n id: 'APPR-005',\n severity: 'medium',\n title: 'File edits auto-approved',\n check(context) {\n return settingsFor(context).flatMap((s) =>\n s.partial.map((p) =>\n finding(\n this,\n s.file,\n p.line,\n `${s.agent} approves some actions without asking: ${p.value}`,\n 'use the default mode in shared project settings; let each developer opt in for their own session',\n ),\n ),\n );\n },\n },\n];\n\nexport const approvalsScanner: Scanner = {\n name: 'approvals',\n rules,\n findTargets: findApprovalsTargets,\n};\n","import { stripBom } from '../../core/text.js';\n\nexport const LOCK_FILE_PATH = '.surfscan/mcp.lock.json';\n/** Server name for an exported list that does not say which server it came from. */\nexport const UNNAMED_SERVER = '*';\n\nexport interface McpTool {\n name: string;\n /** The tool as exported: description, inputSchema and so on. */\n definition: Record<string, unknown>;\n}\n\nexport type ToolList = Record<string, McpTool[]>;\n\n/** Options read from `ScanContext.options`. */\nexport interface ToolSource {\n /** Where the list came from, shown in findings. Omitted when read from running servers. */\n file?: string;\n /** The text of the file, used to find line numbers. */\n content?: string;\n tools: ToolList;\n}\n\nexport type LockFile = { version: 1; servers: Record<string, Record<string, string>> };\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction toTools(value: unknown): McpTool[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((item) => (isObject(item) && typeof item.name === 'string' ? [{ name: item.name, definition: item }] : []));\n}\n\nfunction toolArray(value: unknown): unknown {\n if (Array.isArray(value)) return value;\n if (!isObject(value)) return undefined;\n if (Array.isArray(value.tools)) return value.tools;\n return isObject(value.result) ? value.result.tools : undefined;\n}\n\n/**\n * Accepts a `tools/list` result (`{ \"tools\": [...] }`, optionally inside a\n * JSON-RPC `result`), a bare array, or `{ \"servers\": { \"<name>\": <either> } }`.\n */\nexport function parseToolList(text: string): ToolList {\n const data: unknown = JSON.parse(stripBom(text));\n if (isObject(data) && isObject(data.servers)) {\n return Object.fromEntries(Object.entries(data.servers).map(([name, value]) => [name, toTools(toolArray(value))]));\n }\n const tools = toolArray(data);\n if (!Array.isArray(tools)) {\n throw new Error('expected a tools array or a \"servers\" object');\n }\n return { [UNNAMED_SERVER]: toTools(tools) };\n}\n\n/** Strings an agent reads from a tool definition, including nested parameter descriptions. */\nexport function toolTexts(node: unknown, out: string[] = []): string[] {\n if (Array.isArray(node)) {\n for (const item of node) toolTexts(item, out);\n } else if (isObject(node)) {\n for (const [key, value] of Object.entries(node)) {\n if ((key === 'description' || key === 'title') && typeof value === 'string') out.push(value);\n else toolTexts(value, out);\n }\n }\n return out;\n}\n\nfunction canonical(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonical);\n if (!isObject(value)) return value;\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, canonical(value[key])]),\n );\n}\n\n/** Hash of what the agent is told about a tool. Key order does not change it. */\nexport async function hashTool(tool: McpTool): Promise<string> {\n const { description, inputSchema } = tool.definition;\n const bytes = new TextEncoder().encode(JSON.stringify(canonical({ description, inputSchema })));\n const digest = await globalThis.crypto.subtle.digest('SHA-256', bytes);\n const hex = [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('');\n return `sha256:${hex}`;\n}\n\nexport async function buildLock(tools: ToolList): Promise<LockFile> {\n const servers: LockFile['servers'] = {};\n for (const name of Object.keys(tools).sort()) {\n const hashes: Record<string, string> = {};\n for (const tool of [...tools[name]!].sort((a, b) => a.name.localeCompare(b.name))) {\n hashes[tool.name] = await hashTool(tool);\n }\n servers[name] = hashes;\n }\n return { version: 1, servers };\n}\n\nexport function parseLock(text: string): LockFile {\n const data: unknown = JSON.parse(stripBom(text));\n if (!isObject(data) || !isObject(data.servers)) throw new Error('expected a \"servers\" object');\n return data as LockFile;\n}\n","import type { SourceFile } from '../../core/types.js';\nimport { JsonLocator, parseJsonc } from '../shared-json.js';\n\nexport interface McpServer {\n name: string;\n file: string;\n line: number;\n command?: string;\n args: string[];\n env: Record<string, string>;\n url?: string;\n /** Line of a string belonging to this server. */\n lineOf(value: string): number;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction stringMap(value: unknown): Record<string, string> {\n if (!isObject(value)) return {};\n return Object.fromEntries(Object.entries(value).filter((e): e is [string, string] => typeof e[1] === 'string'));\n}\n\n/** `mcpServers` in .mcp.json and .cursor/mcp.json, `servers` in .vscode/mcp.json. */\nfunction serverMap(path: string, data: Record<string, unknown>): Record<string, unknown> {\n const key = /(?:^|\\/)\\.vscode\\/mcp\\.json$/.test(path) ? 'servers' : 'mcpServers';\n const map = data[key];\n return isObject(map) ? map : {};\n}\n\nexport function parseMcpConfig(file: SourceFile): McpServer[] {\n const data = parseJsonc(file.content);\n if (!isObject(data)) return [];\n const loc = new JsonLocator(file.content);\n const servers: McpServer[] = [];\n for (const [name, value] of Object.entries(serverMap(file.path, data))) {\n if (!isObject(value)) continue;\n const offset = Math.max(0, loc.keyOffset(name));\n const line = loc.key(name);\n servers.push({\n name,\n file: file.path,\n line,\n command: typeof value.command === 'string' ? value.command : undefined,\n args: Array.isArray(value.args) ? value.args.filter((a): a is string => typeof a === 'string') : [],\n env: stringMap(value.env),\n url: typeof value.url === 'string' ? value.url : undefined,\n lineOf: (text) => (loc.keyOffset(text, offset) === -1 ? line : loc.key(text, offset)),\n });\n }\n return servers;\n}\n","[\n \"anthropic.com\", \"asana.com\", \"atlassian.com\", \"cloudflare.com\", \"figma.com\", \"github.com\", \"githubcopilot.com\",\n \"gitlab.com\", \"huggingface.co\", \"intercom.com\", \"linear.app\", \"neon.tech\", \"notion.com\", \"openai.com\", \"paypal.com\",\n \"sentry.dev\", \"sentry.io\", \"stripe.com\", \"supabase.com\", \"vercel.com\", \"zapier.com\"\n]\n","import { listTargets } from '../../core/runner.js';\nimport { excerpt } from '../../core/text.js';\nimport type { Finding, Rule, ScanContext, Scanner, SourceProvider, SurfscanConfig } from '../../core/types.js';\nimport {\n findCredentialAccess,\n findHiddenContent,\n findInstructionOverride,\n findInvisibleChars,\n findPipeToShell,\n findUnpinnedInstalls,\n} from '../rules/patterns.js';\nimport { JsonLocator } from '../shared-json.js';\nimport { matchAll, type TextMatch } from '../shared.js';\nimport { parseMcpConfig, type McpServer } from './config.js';\nimport knownHosts from './known-hosts.json' with { type: 'json' };\nimport { hashTool, LOCK_FILE_PATH, parseLock, toolTexts, type LockFile, type McpTool, type ToolSource } from './tools.js';\n\nexport const MCP_TARGETS = ['**/.mcp.json', '**/.cursor/mcp.json', '**/.vscode/mcp.json'];\n\nexport function findMcpTargets(provider: SourceProvider, config: SurfscanConfig): Promise<string[]> {\n return listTargets(provider, config, MCP_TARGETS);\n}\n\nconst parsed = new WeakMap<ScanContext, McpServer[]>();\n\n/** Every server configured in the discovered files. */\nfunction serversFor(context: ScanContext): McpServer[] {\n const cached = parsed.get(context);\n if (cached) return cached;\n const out: McpServer[] = [];\n for (const file of context.files) {\n try {\n out.push(...parseMcpConfig(file));\n } catch (err) {\n context.warn(`${file.path}: could not parse MCP config (${(err as Error).message})`, { incomplete: true });\n }\n }\n parsed.set(context, out);\n return out;\n}\n\nfunction toolSource(context: ScanContext): ToolSource | undefined {\n return (context.options as { toolSource?: ToolSource }).toolSource;\n}\n\n/** Each tool, with the location its findings should point at. */\nfunction locateTools(context: ScanContext, source: ToolSource): Array<{ server: string; tool: McpTool; file: string; line: number; lineOf(text: string): number }> {\n const servers = serversFor(context);\n const loc = source.content === undefined ? undefined : new JsonLocator(source.content);\n return Object.entries(source.tools).flatMap(([server, tools]) => {\n const configured = servers.find((s) => s.name === server);\n return tools.map((tool) => {\n const line = loc ? loc.key(tool.name) : (configured?.line ?? 0);\n return {\n server,\n tool,\n file: source.file ?? configured?.file ?? server,\n line,\n lineOf: (text: string) => (loc && source.content!.includes(JSON.stringify(text)) ? loc.key(text) : line),\n };\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// MCP-001: injection-style text in tool descriptions\n// ---------------------------------------------------------------------------\n\n/** The `<IMPORTANT>` wrapper from published tool poisoning attacks. */\nconst POISON_TAG = /<\\s*(?:important|system|secret|hidden)\\s*>/gi;\n\nfunction findPoisonTag(text: string): TextMatch[] {\n return [...matchAll(POISON_TAG, text)].map((m) => ({ index: m.index, detail: m[0] }));\n}\n\nconst TEXT_DETECTORS = [findInstructionOverride, findCredentialAccess, findInvisibleChars, findHiddenContent, findPoisonTag];\n\n// ---------------------------------------------------------------------------\n// MCP-003: filesystem access to the home directory or root\n// ---------------------------------------------------------------------------\n\nfunction programName(command: string): string {\n return (command.split(/[\\\\/]/).pop() ?? command).toLowerCase().replace(/\\.(?:exe|cmd|bat)$/, '');\n}\n\nconst isDocker = (server: McpServer): boolean => ['docker', 'podman'].includes(programName(server.command ?? ''));\n\nconst HOME_OR_ROOT =\n /^(?:\\/|~|\\$HOME|\\$\\{HOME\\}|\\$\\{env:HOME\\}|\\$\\{env:USERPROFILE\\}|\\$\\{userHome\\}|%USERPROFILE%|[a-z]:|\\/home\\/[^/]+|\\/Users\\/[^/]+|[a-z]:[\\\\/]Users[\\\\/][^\\\\/]+)$/i;\nconst CREDENTIAL_DIR = /(?:^|[\\\\/])\\.(?:ssh|aws|gnupg|kube)(?:[\\\\/]|$)/i;\n\nexport function isBroadPath(path: string): boolean {\n const trimmed = path.replace(/[\\\\/]+$/, '');\n return HOME_OR_ROOT.test(trimmed === '' ? '/' : trimmed) || CREDENTIAL_DIR.test(path);\n}\n\nfunction mountSource(flag: string, value: string): string | undefined {\n if (flag === '--mount') return /(?:^|,)(?:source|src)=([^,]+)/.exec(value)?.[1];\n // host:container[:options], where a Windows host path has its own colon.\n return /^((?:[a-z]:)?[^:]+):/i.exec(value)?.[1];\n}\n\nfunction broadAccess(server: McpServer): Array<{ what: string; source: string }> {\n const out: Array<{ what: string; source: string }> = [];\n if (isDocker(server)) {\n server.args.forEach((arg, i) => {\n const inline = /^(--volume|--mount)=(.+)$/.exec(arg);\n const flag = inline?.[1] ?? (['-v', '--volume', '--mount'].includes(arg) ? arg : undefined);\n const value = inline?.[2] ?? (flag ? server.args[i + 1] : undefined);\n if (!flag || !value) return;\n const source = mountSource(flag, value);\n if (!source) return;\n if (source.includes('docker.sock')) out.push({ what: 'the Docker socket is mounted, which gives root on the host', source: value });\n else if (isBroadPath(source)) out.push({ what: `host path ${source} is mounted`, source: value });\n });\n } else if (/filesystem|\\bfs\\b/i.test(`${server.name} ${server.command ?? ''} ${server.args.join(' ')}`)) {\n for (const arg of server.args) {\n if (!arg.startsWith('-') && isBroadPath(arg)) out.push({ what: `it can read and write ${arg}`, source: arg });\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// MCP-004: unpinned remote packages\n// ---------------------------------------------------------------------------\n\nconst DOCKER_VALUE_FLAGS = new Set([\n '-e', '--env', '--env-file', '-v', '--volume', '--mount', '--name', '--network', '--net', '-p', '--publish', '-u',\n '--user', '-w', '--workdir', '--entrypoint', '--platform', '-l', '--label', '-m', '--memory', '--cpus', '--add-host',\n '-h', '--hostname', '--pull', '--cap-add', '--cap-drop', '--security-opt',\n]);\n\nexport function dockerImage(args: string[]): string | undefined {\n const run = args.indexOf('run');\n if (run === -1) return undefined;\n for (let i = run + 1; i < args.length; i++) {\n const arg = args[i]!;\n if (!arg.startsWith('-')) return arg;\n if (DOCKER_VALUE_FLAGS.has(arg)) i++;\n }\n return undefined;\n}\n\nfunction imagePinned(image: string): boolean {\n if (image.includes('@sha256:')) return true;\n const tag = /:([^:/]+)$/.exec(image)?.[1];\n return tag !== undefined && /^v?\\d+\\.\\d+/.test(tag);\n}\n\n/** What makes a server's launch command unpinned, or undefined if it is pinned. */\nexport function unpinnedTarget(server: McpServer): string | undefined {\n if (isDocker(server)) {\n const image = dockerImage(server.args);\n return image && !imagePinned(image) ? `container image ${image}` : undefined;\n }\n const launch = [server.command ?? '', ...server.args].join(' ');\n return findUnpinnedInstalls(launch)[0]?.detail ?? findPipeToShell(launch)[0]?.detail;\n}\n\n// ---------------------------------------------------------------------------\n// MCP-005: plain http or unknown host\n// ---------------------------------------------------------------------------\n\nconst LOOPBACK = /^(?:localhost|127(?:\\.\\d+){3}|\\[::1\\]|0\\.0\\.0\\.0|host\\.docker\\.internal)$/i;\nconst KNOWN_HOSTS: readonly string[] = knownHosts;\n\n/** What is wrong with a remote server URL, or undefined if nothing is. */\nexport function remoteProblem(value: string): string | undefined {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return undefined;\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return undefined;\n const host = url.hostname.toLowerCase();\n if (LOOPBACK.test(host)) return undefined;\n if (url.protocol === 'http:') return `connects to ${host} over plain http`;\n const known = KNOWN_HOSTS.some((k) => host === k || host.endsWith(`.${k}`));\n return known ? undefined : `connects to ${host}, which is not on the known host list`;\n}\n\nfunction remoteUrls(server: McpServer): string[] {\n const urls = server.url ? [server.url] : [];\n // Bridges such as mcp-remote take the URL as an argument.\n return [...urls, ...server.args.filter((a) => /^https?:\\/\\//i.test(a))];\n}\n\n// ---------------------------------------------------------------------------\n// Rules\n// ---------------------------------------------------------------------------\n\nasync function readLock(context: ScanContext): Promise<LockFile | undefined> {\n const text = await context.provider.read(LOCK_FILE_PATH);\n if (text === undefined) return undefined;\n try {\n return parseLock(text);\n } catch (err) {\n context.warn(`${LOCK_FILE_PATH}: could not parse lock file (${(err as Error).message})`, { incomplete: true });\n return undefined;\n }\n}\n\nexport const rules: Rule[] = [\n {\n id: 'MCP-001',\n severity: 'high',\n title: 'Injection-style text in tool description',\n check(context) {\n const source = toolSource(context);\n if (!source) return [];\n const out: Finding[] = [];\n for (const { server, tool, file, lineOf } of locateTools(context, source)) {\n for (const text of toolTexts(tool.definition)) {\n const details = new Set(TEXT_DETECTORS.flatMap((detect) => detect(text).map((m) => excerpt(m.detail, 90))));\n for (const detail of details) {\n out.push({\n ruleId: this.id,\n severity: this.severity,\n message: `Tool \"${tool.name}\" (server ${server}) has injection-style text: ${detail}`,\n file,\n line: lineOf(text),\n fix: 'do not use this server until the text is reviewed; agents follow tool descriptions that users never see',\n });\n }\n }\n }\n return out;\n },\n },\n {\n id: 'MCP-002',\n severity: 'high',\n title: 'Tool description changed since the saved lock',\n async check(context) {\n const source = toolSource(context);\n const lock = source ? await readLock(context) : undefined;\n if (!source || !lock) return [];\n const out: Finding[] = [];\n for (const { server, tool, file, line } of locateTools(context, source)) {\n const saved = lock.servers[server]?.[tool.name];\n if (saved === (await hashTool(tool))) continue;\n out.push({\n ruleId: this.id,\n severity: this.severity,\n message: saved\n ? `Tool \"${tool.name}\" (server ${server}) changed since the saved lock`\n : `Tool \"${tool.name}\" (server ${server}) is not in the saved lock`,\n file,\n line,\n fix: 'review the new description; if it is safe, save it with surfscan mcp --update-lock',\n });\n }\n return out;\n },\n },\n {\n id: 'MCP-003',\n severity: 'high',\n title: 'Server with filesystem access to the home directory or root',\n check(context) {\n return serversFor(context).flatMap((s) =>\n broadAccess(s).map(({ what, source }) => ({\n ruleId: this.id,\n severity: this.severity,\n message: `Server \"${s.name}\" reaches too much of the filesystem: ${what}`,\n file: s.file,\n line: s.lineOf(source),\n fix: 'limit the server to the project directory',\n })),\n );\n },\n },\n {\n id: 'MCP-004',\n severity: 'medium',\n title: 'Server launched from an unpinned remote package',\n check(context) {\n const out: Finding[] = [];\n for (const s of serversFor(context)) {\n const target = unpinnedTarget(s);\n if (!target) continue;\n out.push({\n ruleId: this.id,\n severity: this.severity,\n message: `Server \"${s.name}\" runs whatever is newest each time it starts: ${target}`,\n file: s.file,\n line: s.line,\n fix: 'pin an exact version (pkg@1.2.3, pkg==1.2.3) or a container image digest (image@sha256:...)',\n });\n }\n return out;\n },\n },\n {\n id: 'MCP-005',\n severity: 'medium',\n title: 'Server reached over plain http or an unknown host',\n check(context) {\n const out: Finding[] = [];\n for (const s of serversFor(context)) {\n for (const url of remoteUrls(s)) {\n const problem = remoteProblem(url);\n if (!problem) continue;\n out.push({\n ruleId: this.id,\n severity: this.severity,\n message: `Server \"${s.name}\" ${problem}`,\n file: s.file,\n line: s.lineOf(url),\n fix: 'use https, and confirm you trust this host; it controls the tool descriptions your agent reads',\n });\n }\n }\n return out;\n },\n },\n {\n id: 'MCP-006',\n severity: 'info',\n title: 'No lock file yet',\n async check(context) {\n if (serversFor(context).length === 0) return [];\n if ((await context.provider.read(LOCK_FILE_PATH)) !== undefined) return [];\n return [\n {\n ruleId: this.id,\n severity: this.severity,\n message: 'No MCP lock file yet, so tool description changes cannot be detected',\n file: LOCK_FILE_PATH,\n line: 0,\n fix: 'export the tool list and run surfscan mcp --tools <file.json> --update-lock, then commit the lock file',\n },\n ];\n },\n },\n];\n\nexport const mcpScanner: Scanner = {\n name: 'mcp',\n rules,\n findTargets: findMcpTargets,\n};\n","import { stripBom } from '../../core/text.js';\n\nexport const LOCK_FILE_NAMES = ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock'];\n\ntype VersionLookup = (name: string, prefix: string) => string | undefined;\n\nfunction parsePackageLock(content: string): VersionLookup {\n const lock: unknown = JSON.parse(stripBom(content));\n const packages = (lock as { packages?: Record<string, { version?: unknown }> } | null)?.packages;\n return (name, prefix) => {\n const entry = packages?.[`${prefix}node_modules/${name}`] ?? packages?.[`node_modules/${name}`];\n return typeof entry?.version === 'string' ? entry.version : undefined;\n };\n}\n\nconst remember = (map: Map<string, string>, name: string, version: string): void => {\n if (!map.has(name)) map.set(name, version);\n};\n\n// Line-based so that reading a lock file needs no YAML dependency.\nfunction parsePnpmLock(content: string): VersionLookup {\n const importers = new Map<string, string>();\n const packages = new Map<string, string>();\n const lines = content.split(/\\r?\\n/);\n lines.forEach((line, i) => {\n const key = /^[ \\t]+['\"]?((?:@[^\\s'\"/]+\\/)?[^\\s'\"@/:]+)['\"]?:\\s*$/.exec(line);\n if (key && /^\\s+specifier:/.test(lines[i + 1] ?? '')) {\n const version = /^\\s+version:\\s*['\"]?(\\d[^\\s('\"]*)/.exec(lines[i + 2] ?? '');\n if (version) remember(importers, key[1]!, version[1]!);\n }\n const entry = /^[ \\t]+['\"]?\\/?((?:@[^\\s'\"/]+\\/)?[^\\s'\"@/]+)@(\\d[^\\s('\":]*)['\"]?:/.exec(line);\n if (entry) remember(packages, entry[1]!, entry[2]!);\n });\n return (name) => importers.get(name) ?? packages.get(name);\n}\n\nfunction parseYarnLock(content: string): VersionLookup {\n const versions = new Map<string, string>();\n const lines = content.split(/\\r?\\n/);\n lines.forEach((line, i) => {\n const entry = /^\"?((?:@[^/\\s\"]+\\/)?[^@\\s\"]+)@.*:\\s*$/.exec(line);\n const version = entry && /^\\s+version:?\\s+\"?([^\"\\s]+)/.exec(lines[i + 1] ?? '');\n if (version) remember(versions, entry[1]!, version[1]!);\n });\n return (name) => versions.get(name);\n}\n\nconst PARSERS: Record<string, (content: string) => VersionLookup> = {\n 'package-lock.json': parsePackageLock,\n 'pnpm-lock.yaml': parsePnpmLock,\n};\n\n/** One lookup is made per dependency, so each lock file is parsed once. */\nconst parsed = new Map<string, VersionLookup>();\nconst MAX_PARSED = 16;\n\n/** The version a lock file resolves a direct dependency to. `prefix` locates a workspace in a root package-lock. */\nexport function lockedVersion(fileName: string, content: string, name: string, prefix: string): string | undefined {\n let lookup = parsed.get(content);\n if (!lookup) {\n lookup = (PARSERS[fileName] ?? parseYarnLock)(content);\n if (parsed.size >= MAX_PARSED) parsed.clear();\n parsed.set(content, lookup);\n }\n return lookup(name, prefix);\n}\n","export const DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org';\nexport const DEFAULT_DOWNLOADS_URL = 'https://api.npmjs.org/downloads/point/last-week';\n\nconst TIMEOUT_MS = 30_000;\nconst CONCURRENCY = 8;\n\nexport type FetchLike = (\n url: string,\n init?: { headers?: Record<string, string>; signal?: AbortSignal },\n) => Promise<{ ok: boolean; status: number; json(): Promise<unknown> }>;\n\nexport interface PackageVersion {\n scripts: Record<string, string>;\n maintainers: string[];\n deprecated?: string;\n}\n\nexport interface Packument {\n latest?: string;\n created?: string;\n unpublished: boolean;\n versions: Record<string, PackageVersion>;\n /** Publish time of each version. */\n times: Record<string, string>;\n}\n\nexport type Lookup =\n | { status: 'found'; packument: Packument }\n | { status: 'missing' }\n | { status: 'error'; message: string };\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction strings(value: unknown): Record<string, string> {\n if (!isObject(value)) return {};\n return Object.fromEntries(Object.entries(value).filter((e): e is [string, string] => typeof e[1] === 'string'));\n}\n\nfunction maintainerNames(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((m) => {\n if (typeof m === 'string') return [m.replace(/\\s*<.*$/, '')];\n return isObject(m) && typeof m.name === 'string' ? [m.name] : [];\n });\n}\n\n/** Keep only what the rules read; full packuments can be tens of megabytes. */\nexport function toPackument(raw: unknown): Packument {\n const doc = isObject(raw) ? raw : {};\n const time = isObject(doc.time) ? doc.time : {};\n const versions: Record<string, PackageVersion> = {};\n if (isObject(doc.versions)) {\n for (const [version, data] of Object.entries(doc.versions)) {\n const v = isObject(data) ? data : {};\n versions[version] = {\n scripts: strings(v.scripts),\n maintainers: maintainerNames(v.maintainers),\n ...(typeof v.deprecated === 'string' && v.deprecated ? { deprecated: v.deprecated } : {}),\n };\n }\n }\n return {\n latest: strings(doc['dist-tags']).latest,\n created: typeof time.created === 'string' ? time.created : undefined,\n unpublished: time.unpublished !== undefined,\n versions,\n times: strings(time),\n };\n}\n\n/** `@scope/name` is requested as `@scope%2fname`. */\nfunction packagePath(name: string): string {\n return encodeURIComponent(name).replace(/^%40/, '@').replace(/%2F/, '%2f');\n}\n\nexport async function fetchPackument(fetcher: FetchLike, registryUrl: string, name: string): Promise<Lookup> {\n try {\n const res = await fetcher(`${registryUrl}/${packagePath(name)}`, {\n headers: { accept: 'application/json' },\n signal: AbortSignal.timeout(TIMEOUT_MS),\n });\n if (res.status === 404) return { status: 'missing' };\n if (!res.ok) return { status: 'error', message: `HTTP ${res.status}` };\n return { status: 'found', packument: toPackument(await res.json()) };\n } catch (err) {\n return { status: 'error', message: (err as Error).message };\n }\n}\n\n/** Weekly download count, or undefined when it cannot be determined. */\nexport async function fetchWeeklyDownloads(fetcher: FetchLike, downloadsUrl: string, name: string): Promise<number | undefined> {\n try {\n const res = await fetcher(`${downloadsUrl}/${packagePath(name)}`, { signal: AbortSignal.timeout(TIMEOUT_MS) });\n if (!res.ok) return undefined;\n const body = await res.json();\n return isObject(body) && typeof body.downloads === 'number' ? body.downloads : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Map with a limit on simultaneous requests. */\nexport async function mapLimit<T, R>(items: T[], fn: (item: T) => Promise<R>, limit = CONCURRENCY): Promise<R[]> {\n const results = new Array<R>(items.length);\n let next = 0;\n const worker = async (): Promise<void> => {\n while (next < items.length) {\n const i = next++;\n results[i] = await fn(items[i]!);\n }\n };\n await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));\n return results;\n}\n","[\n \"@angular/core\", \"@babel/core\", \"@babel/preset-env\", \"@emotion/react\", \"@modelcontextprotocol/sdk\", \"@nestjs/core\",\n \"@playwright/test\", \"@prisma/client\", \"@tanstack/react-query\", \"@types/node\", \"@types/react\", \"@typescript-eslint/parser\",\n \"async\", \"autoprefixer\", \"axios\", \"bcrypt\", \"bcryptjs\", \"body-parser\", \"bootstrap\", \"chalk\", \"cheerio\",\n \"chokidar\", \"classnames\", \"commander\", \"concurrently\", \"cookie-parser\", \"cors\", \"cross-env\", \"cross-spawn\", \"date-fns\",\n \"dayjs\", \"debug\", \"dotenv\", \"drizzle-orm\", \"electron\", \"esbuild\", \"eslint\", \"express\", \"fast-glob\", \"fastify\", \"firebase\",\n \"form-data\", \"fs-extra\", \"glob\", \"graphql\", \"handlebars\", \"helmet\", \"husky\", \"inquirer\", \"jest\", \"jquery\", \"js-yaml\",\n \"jsonwebtoken\", \"knex\", \"langchain\", \"lint-staged\", \"lodash\", \"mocha\", \"moment\", \"mongodb\", \"mongoose\", \"morgan\", \"multer\",\n \"mysql2\", \"nanoid\", \"next\", \"nodemailer\", \"nodemon\", \"nuxt\", \"openai\", \"passport\", \"pino\", \"playwright\", \"postcss\",\n \"preact\", \"prettier\", \"prisma\", \"prop-types\", \"puppeteer\", \"react\", \"react-dom\", \"react-redux\", \"react-router\",\n \"react-router-dom\", \"redis\", \"redux\", \"request\", \"rimraf\", \"rollup\", \"rxjs\", \"sass\", \"semver\", \"sequelize\", \"server\",\n \"sharp\", \"socket.io\", \"stripe\", \"styled-components\", \"supertest\", \"svelte\", \"tailwindcss\", \"ts-node\", \"tslib\", \"tslint\",\n \"tsup\", \"turbo\", \"typeorm\", \"typescript\", \"underscore\", \"uuid\", \"validator\", \"vite\", \"vitest\", \"webpack\", \"webpack-cli\",\n \"winston\", \"yargs\", \"zod\", \"zustand\"\n]\n","import popular from './popular-packages.json' with { type: 'json' };\n\nconst POPULAR_PACKAGES: readonly string[] = popular;\nconst POPULAR = new Set(POPULAR_PACKAGES);\n/** Below this length one edit changes too much of the name to mean anything. */\nconst MIN_LENGTH = 5;\n\n/** Levenshtein distance of at most 1, counting an adjacent swap as one edit. */\nfunction withinOneEdit(a: string, b: string): boolean {\n if (Math.abs(a.length - b.length) > 1) return false;\n let start = 0;\n while (start < a.length && start < b.length && a[start] === b[start]) start++;\n const restA = a.slice(start);\n const restB = b.slice(start);\n if (restA === restB) return true;\n if (restA.slice(1) === restB.slice(1)) return true;\n if (restA.slice(1) === restB || restA === restB.slice(1)) return true;\n return restA.length >= 2 && restA[0] === restB[1] && restA[1] === restB[0] && restA.slice(2) === restB.slice(2);\n}\n\nconst withoutSeparators = (name: string): string => name.replace(/[-_.]/g, '');\n\n/** The popular package this name looks like a misspelling of, if any. */\nexport function typosquatTarget(name: string): string | undefined {\n const lower = name.toLowerCase();\n if (POPULAR.has(lower)) return undefined;\n return POPULAR_PACKAGES.find(\n (target) =>\n target.length >= MIN_LENGTH && (withinOneEdit(lower, target) || withoutSeparators(lower) === withoutSeparators(target)),\n );\n}\n","import { listTargets } from '../../core/runner.js';\nimport { excerpt, stripBom } from '../../core/text.js';\nimport type { Finding, Rule, ScanContext, Scanner, SourceFile, SourceProvider, SurfscanConfig } from '../../core/types.js';\nimport { JsonLocator } from '../shared-json.js';\nimport { LOCK_FILE_NAMES, lockedVersion } from './lockfile.js';\nimport {\n DEFAULT_DOWNLOADS_URL,\n DEFAULT_REGISTRY_URL,\n fetchPackument,\n fetchWeeklyDownloads,\n mapLimit,\n type FetchLike,\n type Lookup,\n type Packument,\n} from './registry.js';\nimport { typosquatTarget } from './typosquat.js';\n\nexport const DEPS_TARGETS = ['**/package.json', ...LOCK_FILE_NAMES.map((name) => `**/${name}`)];\n\n/** Lock files in healthy projects run to many megabytes. */\nexport const MAX_DEPS_FILE_BYTES = 32 * 1024 * 1024;\n\nexport function findDepsTargets(provider: SourceProvider, config: SurfscanConfig): Promise<string[]> {\n return listTargets(provider, config, DEPS_TARGETS);\n}\n\n/** Options read from `ScanContext.options`. */\nexport interface DepsOptions {\n offline?: boolean;\n fetch?: FetchLike;\n registryUrl?: string;\n downloadsUrl?: string;\n}\n\nconst SECTIONS = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'];\nconst INSTALL_HOOKS = ['preinstall', 'install', 'postinstall'];\nconst NAME = /^(?:@[a-z0-9~-][a-z0-9._~-]*\\/)?[a-z0-9~-][a-z0-9._~-]*$/i;\nconst NOT_FROM_REGISTRY = /^(?:workspace|file|link|portal|git|git\\+\\w+|https?|github|gitlab|bitbucket):|^[^@/\\s]+\\/[^/\\s]+$|^\\.{0,2}\\//i;\nconst EXACT_VERSION = /^[=v]*(\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.+-]+)?)$/;\nconst UNPINNED_SPEC = /^(?:\\*|x|latest|)$/i;\n/** A package this widely used is not a squat, even if its name is close to another. */\nconst ESTABLISHED_WEEKLY_DOWNLOADS = 10_000;\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\ninterface DepRef {\n /** The name on the registry, which differs from the declared one for `npm:` aliases. */\n name: string;\n file: string;\n line: number;\n spec: string;\n /** An exact version the project requests, from the manifest or a lock file. */\n version?: string;\n}\n\ninterface DepsData {\n refs: DepRef[];\n /** Absent in offline mode. */\n lookups?: Map<string, Lookup>;\n options: DepsOptions;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction dirOf(path: string): string {\n const at = path.lastIndexOf('/');\n return at === -1 ? '' : path.slice(0, at);\n}\n\nconst joinPath = (dir: string, name: string): string => (dir ? `${dir}/${name}` : name);\n\n/** The nearest lock files at or above a directory, read through to a version lookup. */\nfunction lockLookup(files: Map<string, SourceFile>, dir: string, context: ScanContext): (name: string) => string | undefined {\n return (name) => {\n let current = dir;\n for (;;) {\n for (const lockName of LOCK_FILE_NAMES) {\n const lock = files.get(joinPath(current, lockName));\n if (!lock) continue;\n const prefix = current === dir ? '' : `${dir.slice(current.length).replace(/^\\//, '')}/`;\n try {\n const version = lockedVersion(lockName, lock.content, name, prefix);\n if (version) return version;\n } catch (err) {\n context.warn(`${lock.path}: could not parse lock file (${(err as Error).message})`, { incomplete: true });\n files.delete(lock.path);\n }\n }\n if (current === '') return undefined;\n current = dirOf(current);\n }\n };\n}\n\n/** Registry URLs from an .npmrc: the default under `''`, and one per scope. */\nfunction parseNpmrc(text: string): Map<string, string> {\n const out = new Map<string, string>();\n for (const line of text.split(/\\r?\\n/)) {\n const m = /^\\s*(?:(@[^:=\\s]+):)?registry\\s*=\\s*(\\S+)/.exec(line);\n if (m) out.set(m[1] ?? '', m[2]!);\n }\n return out;\n}\n\nconst PUBLIC_REGISTRY = /^https?:\\/\\/registry\\.(?:npmjs\\.org|yarnpkg\\.com)\\/?$/i;\n\nfunction usesPrivateRegistry(name: string, npmrc: Map<string, string>): boolean {\n const scope = name.startsWith('@') ? name.slice(0, name.indexOf('/')) : '';\n const url = npmrc.get(scope) ?? npmrc.get('');\n return url !== undefined && !PUBLIC_REGISTRY.test(url);\n}\n\n/** The registry package and spec behind a declared dependency, or undefined for local and URL specs. */\nfunction resolveSpec(declared: string, spec: string): { name: string; spec: string } | undefined {\n const alias = /^npm:((?:@[^/]+\\/)?[^@]+)(?:@(.*))?$/.exec(spec);\n if (alias) return { name: alias[1]!, spec: alias[2] ?? '' };\n return NOT_FROM_REGISTRY.test(spec) ? undefined : { name: declared, spec };\n}\n\nasync function collectRefs(context: ScanContext): Promise<DepRef[]> {\n const byPath = new Map(context.files.map((f) => [f.path, f]));\n const manifests: Array<{ file: SourceFile; data: Record<string, unknown> }> = [];\n for (const file of context.files) {\n if (!file.path.endsWith('package.json')) continue;\n try {\n const data: unknown = JSON.parse(stripBom(file.content));\n if (isObject(data)) manifests.push({ file, data });\n } catch (err) {\n context.warn(`${file.path}: could not parse package.json (${(err as Error).message})`, { incomplete: true });\n }\n }\n\n const workspaceNames = new Set(manifests.map((m) => m.data.name).filter((n): n is string => typeof n === 'string'));\n const rootNpmrc = await context.provider.read('.npmrc').catch(() => undefined);\n const refs: DepRef[] = [];\n const skippedPrivate = new Set<string>();\n\n for (const { file, data } of manifests) {\n const dir = dirOf(file.path);\n const localNpmrc = dir ? await context.provider.read(joinPath(dir, '.npmrc')).catch(() => undefined) : undefined;\n const npmrc = new Map([...parseNpmrc(rootNpmrc ?? ''), ...parseNpmrc(localNpmrc ?? '')]);\n const locked = lockLookup(byPath, dir, context);\n const loc = new JsonLocator(file.content);\n\n for (const section of SECTIONS) {\n const deps = data[section];\n if (!isObject(deps)) continue;\n const from = Math.max(0, loc.keyOffset(section));\n // Keys appear in file order, so each search continues from the last one.\n let cursor = from;\n for (const [declared, rawSpec] of Object.entries(deps)) {\n const offset = loc.keyOffset(declared, cursor);\n if (offset !== -1) cursor = offset;\n if (typeof rawSpec !== 'string') continue;\n const resolved = resolveSpec(declared, rawSpec.trim());\n if (!resolved || workspaceNames.has(resolved.name)) continue;\n if (!NAME.test(resolved.name)) {\n context.warn(`${file.path}: skipped invalid package name \"${excerpt(resolved.name, 60)}\"`);\n continue;\n }\n if (usesPrivateRegistry(resolved.name, npmrc)) {\n skippedPrivate.add(resolved.name);\n continue;\n }\n refs.push({\n name: resolved.name,\n file: file.path,\n line: loc.key(declared, offset === -1 ? from : offset),\n spec: resolved.spec,\n version: EXACT_VERSION.exec(resolved.spec)?.[1] ?? locked(declared),\n });\n }\n }\n }\n if (skippedPrivate.size > 0) {\n context.warn(`deps: skipped ${skippedPrivate.size} package(s) that use a private registry set in .npmrc`);\n }\n return refs;\n}\n\nconst cache = new WeakMap<ScanContext, Promise<DepsData>>();\n\nfunction dataFor(context: ScanContext): Promise<DepsData> {\n const cached = cache.get(context);\n if (cached) return cached;\n const pending = (async (): Promise<DepsData> => {\n const options = context.options as DepsOptions;\n const refs = await collectRefs(context);\n if (options.offline) {\n context.warn('deps: offline, so only DEPS-002 and DEPS-006 ran; the other deps rules need the registry');\n return { refs, options };\n }\n const fetcher = options.fetch ?? (globalThis.fetch as FetchLike);\n const registryUrl = options.registryUrl ?? DEFAULT_REGISTRY_URL;\n const names = [...new Set(refs.map((r) => r.name))];\n const results = await mapLimit(names, (name) => fetchPackument(fetcher, registryUrl, name));\n const lookups = new Map(names.map((name, i) => [name, results[i]!]));\n\n const failed = names.filter((name) => lookups.get(name)!.status === 'error');\n if (failed.length > 0) {\n const first = lookups.get(failed[0]!) as Extract<Lookup, { status: 'error' }>;\n context.warn(\n `deps: results are incomplete, could not check ${failed.length} of ${names.length} package(s) on the registry (${failed[0]}: ${first.message})`,\n { incomplete: true },\n );\n }\n return { refs, lookups, options };\n })();\n cache.set(context, pending);\n return pending;\n}\n\nfunction finding(rule: Pick<Rule, 'id' | 'severity'>, ref: DepRef, message: string, fix: string): Finding {\n return { ruleId: rule.id, severity: rule.severity, message, file: ref.file, line: ref.line, fix };\n}\n\n/** One finding per reference to a package found on the registry. */\nasync function registryFindings(\n context: ScanContext,\n check: (ref: DepRef, packument: Packument) => Finding | undefined,\n): Promise<Finding[]> {\n const { refs, lookups } = await dataFor(context);\n const out: Finding[] = [];\n for (const ref of refs) {\n const lookup = lookups?.get(ref.name);\n if (lookup?.status !== 'found' || lookup.packument.unpublished) continue;\n const result = check(ref, lookup.packument);\n if (result) out.push(result);\n }\n return out;\n}\n\n/** The two most recently published versions, newest first. */\nfunction latestTwoVersions(packument: Packument): [string, string] | undefined {\n const published = Object.keys(packument.versions)\n .filter((v) => packument.times[v] !== undefined)\n .sort((a, b) => Date.parse(packument.times[b]!) - Date.parse(packument.times[a]!));\n return published.length >= 2 ? [published[0]!, published[1]!] : undefined;\n}\n\nexport const rules: Rule[] = [\n {\n id: 'DEPS-001',\n severity: 'high',\n title: 'Package does not exist on the registry',\n async check(context) {\n const { refs, lookups } = await dataFor(context);\n const fix = 'check the name is real before installing; agents invent package names that attackers then register';\n const out: Finding[] = [];\n for (const ref of refs) {\n const lookup = lookups?.get(ref.name);\n if (!lookup || lookup.status === 'error') continue;\n if (lookup.status === 'missing') {\n out.push(finding(this, ref, `\"${ref.name}\" does not exist on the npm registry`, fix));\n } else if (lookup.packument.unpublished) {\n out.push(finding(this, ref, `\"${ref.name}\" was unpublished from the npm registry`, fix));\n } else if (ref.version && !(ref.version in lookup.packument.versions)) {\n out.push(finding(this, ref, `\"${ref.name}\" has no published version ${ref.version}`, fix));\n }\n }\n return out;\n },\n },\n {\n id: 'DEPS-002',\n severity: 'high',\n title: 'Name very close to a popular package',\n async check(context) {\n const { refs, options, lookups } = await dataFor(context);\n const suspects = [...new Set(refs.map((r) => r.name))].filter((name) => typosquatTarget(name));\n const isSuspect = new Set(suspects);\n const established = new Set<string>();\n if (lookups) {\n const fetcher = options.fetch ?? (globalThis.fetch as FetchLike);\n const url = options.downloadsUrl ?? DEFAULT_DOWNLOADS_URL;\n const counts = await mapLimit(suspects, (name) => fetchWeeklyDownloads(fetcher, url, name));\n suspects.forEach((name, i) => {\n if ((counts[i] ?? 0) >= ESTABLISHED_WEEKLY_DOWNLOADS) established.add(name);\n });\n }\n return refs\n .filter((ref) => isSuspect.has(ref.name) && !established.has(ref.name))\n .map((ref) => {\n const target = typosquatTarget(ref.name)!;\n return finding(this, ref, `\"${ref.name}\" is very close to the popular package \"${target}\"`, `confirm you meant this package and not \"${target}\"`);\n });\n },\n },\n {\n id: 'DEPS-003',\n severity: 'medium',\n title: 'Recent maintainer or owner change',\n check(context) {\n return registryFindings(context, (ref, packument) => {\n const pair = latestTwoVersions(packument);\n if (!pair) return undefined;\n const [newest, previous] = pair;\n const before = packument.versions[previous]!.maintainers;\n const added = packument.versions[newest]!.maintainers.filter((m) => !before.includes(m));\n // Older packuments may omit maintainers on a version, which says nothing about a change.\n if (before.length === 0 || added.length === 0) return undefined;\n return finding(\n this,\n ref,\n `\"${ref.name}\" gained maintainer(s) in ${newest}, compared with ${previous}: ${added.join(', ')}`,\n 'review what changed in the newest release, and stay on a version you have reviewed until you are satisfied',\n );\n });\n },\n },\n {\n id: 'DEPS-004',\n severity: 'medium',\n title: 'Newly published package',\n check(context) {\n const { minAgeDays } = context.config.deps;\n const now = Date.now();\n return registryFindings(context, (ref, packument) => {\n const created = Date.parse(packument.created ?? '');\n if (Number.isNaN(created)) return undefined;\n const ageDays = Math.floor((now - created) / DAY_MS);\n if (ageDays >= minAgeDays) return undefined;\n return finding(\n this,\n ref,\n `\"${ref.name}\" was first published ${ageDays} day(s) ago (minimum ${minAgeDays})`,\n 'review the package and its maintainer before using it, or wait until it has a track record',\n );\n });\n },\n },\n {\n id: 'DEPS-005',\n severity: 'medium',\n title: 'Install scripts present',\n check(context) {\n return registryFindings(context, (ref, packument) => {\n const version = ref.version ?? packument.latest;\n const scripts = version ? packument.versions[version]?.scripts : undefined;\n const hook = INSTALL_HOOKS.find((h) => scripts?.[h]);\n if (!hook) return undefined;\n return finding(\n this,\n ref,\n `\"${ref.name}@${version}\" runs a ${hook} script: ${excerpt(scripts![hook]!, 60)}`,\n 'review the script; install with --ignore-scripts or allow only the packages that need it',\n );\n });\n },\n },\n {\n id: 'DEPS-006',\n severity: 'low',\n title: 'Unpinned version',\n async check(context) {\n const { refs } = await dataFor(context);\n return refs\n .filter((ref) => UNPINNED_SPEC.test(ref.spec))\n .map((ref) =>\n finding(\n this,\n ref,\n `\"${ref.name}\" accepts any version (\"${ref.spec}\")`,\n 'pin a version or range, and commit a lock file so that installs are repeatable',\n ),\n );\n },\n },\n {\n id: 'DEPS-007',\n severity: 'low',\n title: 'Deprecated package',\n check(context) {\n return registryFindings(context, (ref, packument) => {\n const version = ref.version ?? packument.latest;\n const deprecated = version ? packument.versions[version]?.deprecated : undefined;\n if (!deprecated) return undefined;\n return finding(\n this,\n ref,\n `\"${ref.name}@${version}\" is deprecated: ${excerpt(deprecated, 80)}`,\n 'move to the suggested replacement or a maintained alternative',\n );\n });\n },\n },\n];\n\nexport const depsScanner: Scanner = {\n name: 'deps',\n rules,\n findTargets: findDepsTargets,\n maxFileBytes: MAX_DEPS_FILE_BYTES,\n};\n"],"mappings":"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","names":["rules","rules","isObject","isObject","parsed","rules","parsed","isObject","isObject","finding","rules"]}