/** * Security Scanner - SMI-587, SMI-685, SMI-882, SMI-1189 * * Security scanning for skill content with advanced pattern detection. */ import type { ScanReport, ScannerOptions } from './types.js'; import type { LineContext } from './SecurityScanner.helpers.js'; import { analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode } from './SecurityScanner.helpers.js'; import { extractUrls } from './SecurityScanner.urls.js'; import { calculateRiskScore } from './SecurityScanner.risk-score.js'; import { scanSsrfPatterns } from './SecurityScanner.ssrf.js'; import { toMinimalRefs, toSARIF, toGitHubAnnotations, toSummary } from './SecurityScanner.formatters.js'; export { LineContext, analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode, calculateRiskScore, extractUrls, }; export { scanSsrfPatterns }; export { toMinimalRefs, toSARIF, toGitHubAnnotations, toSummary }; /** * SMI-5879 (design §5): quickCheck is a fast pre-filter, not the full scan — * a bare mention-tier match (a documentation page discussing "jailbreak" or * "DAN") should not by itself fail the quick path. Derived ONCE at module * load, not hand-maintained, so it can never silently drift from * JAILBREAK_PATTERNS' own evidence-tier classification. */ export declare const DIRECTIVE_JAILBREAK_PATTERNS: readonly RegExp[]; export declare class SecurityScanner { private allowedDomains; private blockedPatterns; private maxContentLength; private riskThreshold; constructor(options?: ScannerOptions); private isAllowedDomain; private scanUrls; private scanJailbreakPatterns; private scanSuspiciousPatterns; private scanAIDefenceVulnerabilities; /** @deprecated Use standalone calculateRiskScore function for new code */ calculateRiskScore: typeof calculateRiskScore; /** * Run every content-scanning detector against `content` and return the * combined findings. Factored out of `scan()` (SMI-6033 Wave 2, Gap 2) so * the encoded-payload detector's recursive rescan of DECODED content can * reuse the exact same detector suite instead of a parallel, narrower * reimplementation. * * `skipEncodedPayload` is the STRUCTURAL depth-1 recursion guarantee: the * recursive callback passed to `scanEncodedPayload` below always calls this * method with `skipEncodedPayload: true`, so a base64 blob discovered * INSIDE already-decoded content can never itself be decoded — the inner * call cannot reach `scanEncodedPayload` again no matter what the decoded * text contains. This disables ONLY the encoded-payload detector on the * inner call, not the rest of the suite — a decoded `curl|bash` still * trips `code_execution`, decoded secrets still trip `sensitive_path`, etc. * * SMI-5879: `EncodedPayloadRescanner`'s contract is a bare * `SecurityFinding[]` return (SecurityScanner.encoding.ts, out of scope for * this change), so a recursive `runDetectors` call for decoded content has * no return channel of its own to report multiline truncation. * `truncationRef` is a shared mutable out-param instead: every call (outer * and any recursive rescan) ORs its own jailbreak/AI-defence truncation * into it, so truncation anywhere in the recursion is visible to the * original (outermost) caller. Per `ScanReport.multilineTruncated`'s own * doc: being truncated is only ever used to RAISE caution, never to lower * it, so over-reporting here (e.g. attributing an inner rescan's * truncation to the whole document) is safe by that same design. */ private runDetectors; /** * SMI-6033 Wave 3 (Gap 5): `isHighTrustAuthor` (default `false`) is the * Gatekeeper-bypass trust-tier carve-out — see `scanGatekeeperBypass`'s own * header (`SecurityScanner.compound.ts`) for the full policy. No in-repo * caller of this method currently has a verified author signal to pass * here (the indexer scans via the edge twin, not this core class); the * parameter exists so a future verified-author caller can opt in, and so * every existing call site (skill_validate, skill_rescan, * bundled-sibling-scan, skill-installation.*) defaults closed by * construction, not by convention. * * SMI-6033 Wave 2 (Gap 8) fix (2026-08-17): `isMarkdown` defaults `true`, * preserving byte-identical behavior for every existing caller. Pass * `false` when `content` is a real source file, not markdown — see * `analyzeMarkdownContext`'s own header (SecurityScanner.helpers.ts) for * why the markdown-only indented-code-block heuristic must never apply to * non-markdown content. `bundled-sibling-scan.ts`'s * `collectExecutableCodeFiles` candidates are the first real caller. */ scan(skillId: string, content: string, isHighTrustAuthor?: boolean, isMarkdown?: boolean): ScanReport; /** * SMI-5879 (design §5): tests only the directive-tier derived subset (a * bare mention like "jailbreak" or "DAN" alone should not fail the quick * path — see DIRECTIVE_JAILBREAK_PATTERNS above). */ quickCheck(content: string): boolean; addAllowedDomain(domain: string): void; addBlockedPattern(pattern: RegExp): void; static toMinimalRefs: typeof toMinimalRefs; static toSARIF: typeof toSARIF; static toGitHubAnnotations: typeof toGitHubAnnotations; static toSummary: typeof toSummary; } export default SecurityScanner; //# sourceMappingURL=SecurityScanner.d.ts.map