hackmyagent 0.11.10 → 0.11.12
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/README.md +7 -7
- package/dist/cli.js +6 -6
- package/dist/hardening/scanner.d.ts +1 -1
- package/dist/hardening/scanner.d.ts.map +1 -1
- package/dist/hardening/scanner.js +192 -1
- package/dist/hardening/scanner.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/telemetry/contribute.d.ts +9 -34
- package/dist/telemetry/contribute.d.ts.map +1 -1
- package/dist/telemetry/contribute.js +22 -124
- package/dist/telemetry/contribute.js.map +1 -1
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
6
6
|
[](https://github.com/opena2a-org/hackmyagent)
|
|
7
7
|
|
|
8
|
-
**
|
|
8
|
+
**204 security checks for AI agents. Find what can go wrong before an attacker does.**
|
|
9
9
|
|
|
10
10
|
Security scanner and red-team toolkit for Claude Code, Cursor, VS Code, and any MCP server setup.
|
|
11
11
|
|
|
@@ -31,7 +31,7 @@ npx opena2a-cli review
|
|
|
31
31
|
|
|
32
32
|
**Attack testing** -- 115 adversarial payloads across 11 categories (prompt injection, data exfiltration, jailbreak, MCP exploitation, supply chain, memory weaponization, A2A protocol attacks, context window attacks).
|
|
33
33
|
|
|
34
|
-
**Static analysis** --
|
|
34
|
+
**Static analysis** -- 204 security checks across 60 categories covering credentials, MCP configs, OpenClaw/NemoClaw, Unicode steganography, CVE detection, governance, supply chain, memory poisoning, agent identity, and sandbox escape patterns.
|
|
35
35
|
|
|
36
36
|
<details>
|
|
37
37
|
<summary>Attack testing details (115 payloads)</summary>
|
|
@@ -49,7 +49,7 @@ npx opena2a-cli review
|
|
|
49
49
|
</details>
|
|
50
50
|
|
|
51
51
|
<details>
|
|
52
|
-
<summary>Static analysis details (
|
|
52
|
+
<summary>Static analysis details (204 checks)</summary>
|
|
53
53
|
|
|
54
54
|
- **Unicode steganography** -- invisible codepoints, zero-width chars, bidi attacks, homoglyph confusables, GlassWorm decoders ([real-world: os-info-checker-es6 npm attack, May 2025](https://thehackernews.com/2025/05/malicious-npm-package-leverages-unicode.html))
|
|
55
55
|
- **Hardcoded credentials** -- API keys, tokens, and passwords in source or config files
|
|
@@ -65,7 +65,7 @@ npx opena2a-cli review
|
|
|
65
65
|
|
|
66
66
|
</details>
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
204 checks across 60 categories. 115 attack payloads. No flags needed.
|
|
69
69
|
|
|
70
70
|
---
|
|
71
71
|
|
|
@@ -88,7 +88,7 @@ npm install --save-dev hackmyagent
|
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
┌──────────────────────────────────────────┐
|
|
91
|
-
│ HackMyAgent v0.11.
|
|
91
|
+
│ HackMyAgent v0.11.10 — Security Scanner │
|
|
92
92
|
│ Found: 3 critical · 5 high · 12 medium │
|
|
93
93
|
│ │
|
|
94
94
|
│ CRED-001 critical Hardcoded API key in .env │
|
|
@@ -107,7 +107,7 @@ npm install --save-dev hackmyagent
|
|
|
107
107
|
|
|
108
108
|
Step-by-step guides for common workflows:
|
|
109
109
|
|
|
110
|
-
- **[Scan my agent](docs/use-cases/scan-my-agent.md)** -- Run all
|
|
110
|
+
- **[Scan my agent](docs/use-cases/scan-my-agent.md)** -- Run all 204 checks and auto-fix findings (5 min)
|
|
111
111
|
- **[Red-team MCP servers](docs/use-cases/red-team-mcp.md)** -- Test MCP servers with adversarial payloads (10 min)
|
|
112
112
|
- **[Secure OpenClaw](docs/use-cases/openclaw-security.md)** -- Auto-detected when OpenClaw files are present. Includes CVE detection and ClawHavoc IOC scanning (10 min)
|
|
113
113
|
- **[CI/CD pipeline](docs/use-cases/ci-pipeline.md)** -- GitHub Actions with JSON/SARIF output (5 min)
|
|
@@ -281,7 +281,7 @@ hackmyagent harden-soul --dry-run # preview without writing
|
|
|
281
281
|
|
|
282
282
|
### OpenClaw and NemoClaw Detection
|
|
283
283
|
|
|
284
|
-
`hackmyagent secure` auto-detects OpenClaw and NemoClaw installations by looking for `.openclaw/`, `.moltbot/`, `.nemoclaw/`, `openclaw.json`, and `openclaw.plugin.json`. When detected, it automatically runs platform-specific checks (28 NemoClaw checks, 34 OpenClaw checks) alongside the standard
|
|
284
|
+
`hackmyagent secure` auto-detects OpenClaw and NemoClaw installations by looking for `.openclaw/`, `.moltbot/`, `.nemoclaw/`, `openclaw.json`, and `openclaw.plugin.json`. When detected, it automatically runs platform-specific checks (28 NemoClaw checks, 34 OpenClaw checks) alongside the standard 204 security checks. No separate commands needed.
|
|
285
285
|
|
|
286
286
|
|
|
287
287
|
---
|
package/dist/cli.js
CHANGED
|
@@ -118,7 +118,7 @@ program
|
|
|
118
118
|
.name('hackmyagent')
|
|
119
119
|
.description(`Find it. Break it. Fix it.
|
|
120
120
|
|
|
121
|
-
The hacker's toolkit for AI agents.
|
|
121
|
+
The hacker's toolkit for AI agents. 204 security checks, 115 attack
|
|
122
122
|
payloads, auto-fix with rollback, and OASB benchmark compliance.
|
|
123
123
|
|
|
124
124
|
Documentation: https://hackmyagent.com/docs
|
|
@@ -127,10 +127,10 @@ Updates (v${index_1.VERSION}):
|
|
|
127
127
|
- NemoClaw sandbox scanner (28 installation checks)
|
|
128
128
|
- 10 new static analysis patterns (NEMO series)
|
|
129
129
|
- Community trust contributions
|
|
130
|
-
-
|
|
130
|
+
- 204 checks across 60 categories
|
|
131
131
|
|
|
132
132
|
Examples:
|
|
133
|
-
$ hackmyagent secure Find vulnerabilities (
|
|
133
|
+
$ hackmyagent secure Find vulnerabilities (204 checks)
|
|
134
134
|
$ hackmyagent attack --local Break it with 115 attack payloads
|
|
135
135
|
$ hackmyagent secure --fix Fix issues automatically
|
|
136
136
|
$ hackmyagent fix-all Run all security plugins
|
|
@@ -139,7 +139,7 @@ Examples:
|
|
|
139
139
|
.option('--no-color', 'Disable colored output (also respects NO_COLOR env)');
|
|
140
140
|
program.addHelpText('beforeAll', `
|
|
141
141
|
Quick start:
|
|
142
|
-
$ hackmyagent secure Scan current directory (
|
|
142
|
+
$ hackmyagent secure Scan current directory (204 checks)
|
|
143
143
|
$ hackmyagent fix-all --with-aim Auto-fix + create agent identity
|
|
144
144
|
$ hackmyagent attack Red-team your agent
|
|
145
145
|
`);
|
|
@@ -1695,7 +1695,7 @@ program
|
|
|
1695
1695
|
.command('secure')
|
|
1696
1696
|
.description(`Scan and harden your agent setup
|
|
1697
1697
|
|
|
1698
|
-
Performs
|
|
1698
|
+
Performs 204 security checks across 60 categories:
|
|
1699
1699
|
• Credentials: API key exposure, secrets in configs
|
|
1700
1700
|
• MCP: Server configs, tool permissions, secrets
|
|
1701
1701
|
• Network: TLS, interface bindings, CORS
|
|
@@ -4303,7 +4303,7 @@ Examples:
|
|
|
4303
4303
|
console.log(`\n Detected: ${result.tool}\n`);
|
|
4304
4304
|
console.log(` Added HackMyAgent MCP server to ${result.configPath}\n`);
|
|
4305
4305
|
console.log(` Available tools in ${result.tool}:`);
|
|
4306
|
-
console.log(` hackmyagent_scan —
|
|
4306
|
+
console.log(` hackmyagent_scan — 204 checks + structural analysis`);
|
|
4307
4307
|
console.log(` hackmyagent_deep_scan — Full analysis with LLM reasoning`);
|
|
4308
4308
|
console.log(` hackmyagent_analyze_file — Analyze a single file`);
|
|
4309
4309
|
console.log(` hackmyagent_benchmark — OASB-1 compliance assessment\n`);
|
|
@@ -123,7 +123,7 @@ export declare class HardeningScanner {
|
|
|
123
123
|
*/
|
|
124
124
|
private findSkillFiles;
|
|
125
125
|
/**
|
|
126
|
-
* OpenClaw skill security checks (SKILL-001 to SKILL-
|
|
126
|
+
* OpenClaw skill security checks (SKILL-001 to SKILL-024)
|
|
127
127
|
*/
|
|
128
128
|
private checkOpenclawSkills;
|
|
129
129
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/hardening/scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,UAAU,EAA0C,MAAM,kBAAkB,CAAC;AAwG3F,0CAA0C;AAC1C,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,oDAAoD;IACpD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoID,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAiB;IAEhC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CA2BlC;IAEF;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;OAEG;YACW,aAAa;IAa3B;;OAEG;IACH,OAAO,CAAC,aAAa;IASf,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;YAkZvC,cAAc;IAwE5B;;OAEG;YACW,iBAAiB;IA+F/B;;OAEG;IACH,OAAO,CAAC,gBAAgB;YAeV,uBAAuB;YAoGvB,aAAa;YAiDb,cAAc;YAiGd,oBAAoB;YAyDpB,gBAAgB;YAgJhB,oBAAoB;YAkFpB,gBAAgB;YA8IhB,mBAAmB;YA8EnB,iBAAiB;YA0CjB,iBAAiB;YAiEjB,wBAAwB;YA6FxB,wBAAwB;YAqExB,wBAAwB;YAyHxB,oBAAoB;YAmHpB,uBAAuB;YA4IvB,iBAAiB;YAkHjB,oBAAoB;YA0HpB,mBAAmB;YAqGnB,gBAAgB;YAwIhB,oBAAoB;YAwIpB,gBAAgB;YA6HhB,qBAAqB;YAmHrB,eAAe;IAqI7B;;OAEG;YACW,mBAAmB;IAkHjC;;OAEG;YACW,oBAAoB;IAqKlC;;OAEG;YACW,iBAAiB;IAgJ/B;;OAEG;YACW,oBAAoB;IA4IlC;;OAEG;YACW,eAAe;IAyJ7B;;OAEG;YACW,eAAe;IA2I7B;;OAEG;YACW,eAAe;IA6G7B;;OAEG;YACW,mBAAmB;IAuHjC,OAAO,CAAC,cAAc;IAsBtB;;OAEG;YACW,YAAY;IAmE1B;;OAEG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6DhD;;;OAGG;YACW,cAAc;IAgD5B;;OAEG;YACW,mBAAmB;
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/hardening/scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -4105,7 +4105,7 @@ dist/
|
|
|
4105
4105
|
return skillFiles;
|
|
4106
4106
|
}
|
|
4107
4107
|
/**
|
|
4108
|
-
* OpenClaw skill security checks (SKILL-001 to SKILL-
|
|
4108
|
+
* OpenClaw skill security checks (SKILL-001 to SKILL-024)
|
|
4109
4109
|
*/
|
|
4110
4110
|
async checkOpenclawSkills(targetDir, autoFix) {
|
|
4111
4111
|
const findings = [];
|
|
@@ -4543,6 +4543,197 @@ dist/
|
|
|
4543
4543
|
}
|
|
4544
4544
|
}
|
|
4545
4545
|
}
|
|
4546
|
+
// SKILL-020: Missing/invalid frontmatter
|
|
4547
|
+
const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
4548
|
+
if (!fmMatch) {
|
|
4549
|
+
findings.push({
|
|
4550
|
+
checkId: 'SKILL-020',
|
|
4551
|
+
name: 'Missing YAML Frontmatter',
|
|
4552
|
+
description: 'Skill file lacks required YAML frontmatter for capability declaration',
|
|
4553
|
+
category: 'skill',
|
|
4554
|
+
severity: 'high',
|
|
4555
|
+
passed: false,
|
|
4556
|
+
message: `${relativePath}: Skill file lacks required YAML frontmatter (---). Add frontmatter with name, version, and capabilities fields.`,
|
|
4557
|
+
file: relativePath,
|
|
4558
|
+
fixable: true,
|
|
4559
|
+
fix: 'Add YAML frontmatter block with name, version, and capabilities fields',
|
|
4560
|
+
guidance: 'Skills without frontmatter cannot declare their capabilities, making permission validation impossible. Add a --- delimited YAML block at the top of the file.',
|
|
4561
|
+
});
|
|
4562
|
+
}
|
|
4563
|
+
else {
|
|
4564
|
+
const fmRaw = fmMatch[1];
|
|
4565
|
+
const requiredFields = ['name', 'version', 'capabilities'];
|
|
4566
|
+
const missingFields = requiredFields.filter(f => !new RegExp(`^${f}:`, 'm').test(fmRaw));
|
|
4567
|
+
if (missingFields.length > 0) {
|
|
4568
|
+
findings.push({
|
|
4569
|
+
checkId: 'SKILL-020',
|
|
4570
|
+
name: 'Incomplete Frontmatter',
|
|
4571
|
+
description: 'Skill frontmatter is missing required fields',
|
|
4572
|
+
category: 'skill',
|
|
4573
|
+
severity: 'high',
|
|
4574
|
+
passed: false,
|
|
4575
|
+
message: `${relativePath}: Missing required frontmatter fields: ${missingFields.join(', ')}. These are needed for capability declaration and version tracking.`,
|
|
4576
|
+
file: relativePath,
|
|
4577
|
+
fixable: true,
|
|
4578
|
+
fix: `Add missing fields to frontmatter: ${missingFields.join(', ')}`,
|
|
4579
|
+
guidance: 'Incomplete frontmatter prevents proper capability validation. Every skill should declare name, version, and capabilities.',
|
|
4580
|
+
});
|
|
4581
|
+
}
|
|
4582
|
+
else {
|
|
4583
|
+
findings.push({
|
|
4584
|
+
checkId: 'SKILL-020',
|
|
4585
|
+
name: 'Valid Frontmatter',
|
|
4586
|
+
description: 'Skill file has valid YAML frontmatter with required fields',
|
|
4587
|
+
category: 'skill',
|
|
4588
|
+
severity: 'high',
|
|
4589
|
+
passed: true,
|
|
4590
|
+
message: 'Skill has valid frontmatter with name, version, and capabilities',
|
|
4591
|
+
file: relativePath,
|
|
4592
|
+
fixable: false,
|
|
4593
|
+
fix: 'No action needed',
|
|
4594
|
+
guidance: 'Skill frontmatter is properly configured.',
|
|
4595
|
+
});
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
// SKILL-021: Overprivileged permissions (dangerous capability combinations)
|
|
4599
|
+
const dangerousCombos = [
|
|
4600
|
+
{
|
|
4601
|
+
combo: ['filesystem:*', 'network:outbound'],
|
|
4602
|
+
reason: 'filesystem:* + network:outbound enables data exfiltration',
|
|
4603
|
+
},
|
|
4604
|
+
{
|
|
4605
|
+
combo: ['credential:read', 'network:outbound'],
|
|
4606
|
+
reason: 'credential:read + network:outbound enables credential exfiltration',
|
|
4607
|
+
},
|
|
4608
|
+
];
|
|
4609
|
+
const capPatterns = content.match(/(?:filesystem|network|credential|tool):[a-z*]+/g) || [];
|
|
4610
|
+
const allCaps = [...new Set(capPatterns)];
|
|
4611
|
+
// Also include capabilities from frontmatter if parsed
|
|
4612
|
+
const declaredCapsForPriv = (0, skill_capability_validator_1.parseDeclaredCapabilities)(content);
|
|
4613
|
+
for (const dc of declaredCapsForPriv.capabilities) {
|
|
4614
|
+
if (!allCaps.includes(dc))
|
|
4615
|
+
allCaps.push(dc);
|
|
4616
|
+
}
|
|
4617
|
+
for (const { combo, reason } of dangerousCombos) {
|
|
4618
|
+
const matchCap = (actual, pattern) => {
|
|
4619
|
+
if (actual === pattern)
|
|
4620
|
+
return true;
|
|
4621
|
+
if (pattern.endsWith(':*'))
|
|
4622
|
+
return actual.startsWith(pattern.slice(0, -1));
|
|
4623
|
+
if (actual.endsWith(':*'))
|
|
4624
|
+
return pattern.startsWith(actual.slice(0, -1));
|
|
4625
|
+
return false;
|
|
4626
|
+
};
|
|
4627
|
+
const hasFirst = allCaps.some(c => matchCap(c, combo[0]));
|
|
4628
|
+
const hasSecond = allCaps.some(c => matchCap(c, combo[1]));
|
|
4629
|
+
if (hasFirst && hasSecond) {
|
|
4630
|
+
findings.push({
|
|
4631
|
+
checkId: 'SKILL-021',
|
|
4632
|
+
name: 'Overprivileged Permissions',
|
|
4633
|
+
description: 'Skill has dangerous capability combination that enables exfiltration',
|
|
4634
|
+
category: 'skill',
|
|
4635
|
+
severity: 'high',
|
|
4636
|
+
passed: false,
|
|
4637
|
+
message: `${relativePath}: ${reason}. Restrict filesystem access to specific paths or remove outbound network access.`,
|
|
4638
|
+
file: relativePath,
|
|
4639
|
+
fixable: false,
|
|
4640
|
+
fix: 'Restrict capabilities to minimum required permissions',
|
|
4641
|
+
guidance: 'Dangerous capability combinations can enable data or credential exfiltration. Follow the principle of least privilege.',
|
|
4642
|
+
});
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
// SKILL-022: Environment variable exfiltration
|
|
4646
|
+
const envAccessPatterns = [
|
|
4647
|
+
/process\.env/,
|
|
4648
|
+
/os\.environ/,
|
|
4649
|
+
/\$ENV\{/,
|
|
4650
|
+
/System\.getenv/,
|
|
4651
|
+
/printenv/,
|
|
4652
|
+
/\$\(env\)/,
|
|
4653
|
+
/\$\(printenv/,
|
|
4654
|
+
/\$HOME\b/,
|
|
4655
|
+
/\$\{[A-Z_]+\}/,
|
|
4656
|
+
];
|
|
4657
|
+
const outboundPatterns = [
|
|
4658
|
+
/network:outbound/,
|
|
4659
|
+
/fetch\s*\(/,
|
|
4660
|
+
/https?:\/\//,
|
|
4661
|
+
/XMLHttpRequest/,
|
|
4662
|
+
/\.send\s*\(/,
|
|
4663
|
+
/curl\s/,
|
|
4664
|
+
/wget\s/,
|
|
4665
|
+
];
|
|
4666
|
+
const hasEnvAccess = envAccessPatterns.some(p => p.test(content));
|
|
4667
|
+
const hasOutbound = outboundPatterns.some(p => p.test(content));
|
|
4668
|
+
if (hasEnvAccess && hasOutbound) {
|
|
4669
|
+
findings.push({
|
|
4670
|
+
checkId: 'SKILL-022',
|
|
4671
|
+
name: 'Environment Variable Exfiltration Risk',
|
|
4672
|
+
description: 'Skill accesses environment variables and has outbound network capability',
|
|
4673
|
+
category: 'skill',
|
|
4674
|
+
severity: 'critical',
|
|
4675
|
+
passed: false,
|
|
4676
|
+
message: `${relativePath}: Skill accesses environment variables AND has outbound network capability. This combination can exfiltrate secrets via network requests.`,
|
|
4677
|
+
file: relativePath,
|
|
4678
|
+
fixable: false,
|
|
4679
|
+
fix: 'Remove outbound network access or environment variable reads',
|
|
4680
|
+
guidance: 'Skills that read environment variables and send data externally can exfiltrate API keys, tokens, and other secrets stored in environment variables.',
|
|
4681
|
+
});
|
|
4682
|
+
}
|
|
4683
|
+
// SKILL-023: Obfuscated code patterns
|
|
4684
|
+
const obfuscationPatterns = [
|
|
4685
|
+
{ pattern: /atob\s*\(/, label: 'atob() base64 decode' },
|
|
4686
|
+
{ pattern: /Buffer\.from\s*\(/, label: 'Buffer.from() decode' },
|
|
4687
|
+
{ pattern: /eval\s*\(/, label: 'eval() dynamic execution' },
|
|
4688
|
+
{ pattern: /String\.fromCharCode/, label: 'String.fromCharCode obfuscation' },
|
|
4689
|
+
{ pattern: /\\x[0-9a-fA-F]{2}/, label: 'hex-encoded string' },
|
|
4690
|
+
{ pattern: /(?:atob|Buffer\.from)\s*\([^)]+\)[\s\S]*?eval\s*\(/, label: 'base64+eval combo' },
|
|
4691
|
+
{ pattern: /base64\s+-d/, label: 'shell base64 decode' },
|
|
4692
|
+
{ pattern: /eval\s+\$\(/, label: 'shell eval $(...)' },
|
|
4693
|
+
{ pattern: /\becho\s+['"][A-Za-z0-9+/=]{20,}['"]\s*\|\s*base64/, label: 'echo+base64 pipe' },
|
|
4694
|
+
{ pattern: /new\s+Function\s*\(/, label: 'new Function() dynamic execution' },
|
|
4695
|
+
];
|
|
4696
|
+
for (const { pattern, label } of obfuscationPatterns) {
|
|
4697
|
+
if (pattern.test(content)) {
|
|
4698
|
+
findings.push({
|
|
4699
|
+
checkId: 'SKILL-023',
|
|
4700
|
+
name: 'Obfuscated Code Pattern',
|
|
4701
|
+
description: 'Skill contains obfuscated code that may hide malicious behavior',
|
|
4702
|
+
category: 'skill',
|
|
4703
|
+
severity: 'high',
|
|
4704
|
+
passed: false,
|
|
4705
|
+
message: `${relativePath}: Detected ${label}. Obfuscated code in skills can hide malicious behavior and should be reviewed.`,
|
|
4706
|
+
file: relativePath,
|
|
4707
|
+
fixable: false,
|
|
4708
|
+
fix: 'Replace obfuscated code with readable equivalent',
|
|
4709
|
+
guidance: 'Obfuscated code (base64 decode, eval, hex-encoded strings) in skills is a strong indicator of hidden malicious behavior. Review and replace with transparent code.',
|
|
4710
|
+
});
|
|
4711
|
+
break; // One finding per file for obfuscation
|
|
4712
|
+
}
|
|
4713
|
+
}
|
|
4714
|
+
// SKILL-024: Unbounded tool chaining
|
|
4715
|
+
const hasToolChain = allCaps.some(c => c.includes('tool:chain'));
|
|
4716
|
+
if (hasToolChain) {
|
|
4717
|
+
const hasFm = !!fmMatch;
|
|
4718
|
+
const fmContent = hasFm ? fmMatch[1] : '';
|
|
4719
|
+
const hasMaxIterations = hasFm && (/maxIterations/i.test(fmContent) ||
|
|
4720
|
+
/iterationLimit/i.test(fmContent));
|
|
4721
|
+
if (!hasMaxIterations) {
|
|
4722
|
+
findings.push({
|
|
4723
|
+
checkId: 'SKILL-024',
|
|
4724
|
+
name: 'Unbounded Tool Chaining',
|
|
4725
|
+
description: 'Skill declares tool:chain capability without iteration limits',
|
|
4726
|
+
category: 'skill',
|
|
4727
|
+
severity: 'medium',
|
|
4728
|
+
passed: false,
|
|
4729
|
+
message: `${relativePath}: Skill declares tool:chain capability without maxIterations or iterationLimit. Unbounded chaining can lead to infinite loops or resource exhaustion.`,
|
|
4730
|
+
file: relativePath,
|
|
4731
|
+
fixable: true,
|
|
4732
|
+
fix: 'Add maxIterations or iterationLimit to skill frontmatter',
|
|
4733
|
+
guidance: 'Tool chaining without iteration limits can cause infinite loops, resource exhaustion, or runaway costs. Set a reasonable maxIterations value in frontmatter.',
|
|
4734
|
+
});
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4546
4737
|
}
|
|
4547
4738
|
return findings;
|
|
4548
4739
|
}
|