Audit Summary
Scanned 6 files in ./src/skills for bugs, security vulnerabilities, and performance issues.
Findings
| Severity |
Count |
| Critical |
1 |
| High |
2 |
| Medium |
2 |
| Low |
1 |
Detailed Findings
Critical
| File |
Line |
Issue |
discoverer.js |
29, 50, 63 |
Unsafe YAML parsing — yaml.load() can execute arbitrary JavaScript from crafted SKILL.md files (e.g., !!js/function tags). Should use safe schema: yaml.load(yamlStr, { schema: yaml.JSON_SCHEMA }) or equivalent. |
High
| File |
Line |
Issue |
registry.js |
51-54 |
Silently dropped skills — Invalid (non-skip) skills are excluded from the results array but only logged to #errors. The discover() return value is inconsistent with register() which always returns results for all discovered skills. Callers have no way to know these skills were rejected without calling getErrors(). |
validator.js |
110 |
Input mutation — skill.name = String(skill.name) mutates the caller's object. Side effect that could cause issues if the caller reuses the object. |
Medium
| File |
Line |
Issue |
discoverer.js |
179 |
Shadowing logic asymmetry — Only overrides when new skill is in .agents/skills. If project-level skill is discovered first, user-level skill is silently dropped. Should check both directions. |
registry.js |
140 |
Sync I/O in async context — readFileSync in getSkillBody() blocks the event loop. Acceptable for small files but could be problematic for large SKILL.md files. |
Low
| File |
Line |
Issue |
discoverer.js |
92-100 |
Sync FS operations — readdirSync, statSync, existsSync, readFileSync throughout. Acceptable for skills directory (small scope) but worth noting for consistency. |
Clean Files
index.js — Re-exports only, no issues
permissions.js — Clean permission resolution logic
types.js — Clean Zod schemas, no issues
Audit Summary
Scanned 6 files in
./src/skillsfor bugs, security vulnerabilities, and performance issues.Findings
Detailed Findings
Critical
discoverer.jsyaml.load()can execute arbitrary JavaScript from crafted SKILL.md files (e.g.,!!js/functiontags). Should use safe schema:yaml.load(yamlStr, { schema: yaml.JSON_SCHEMA })or equivalent.High
registry.jsresultsarray but only logged to#errors. Thediscover()return value is inconsistent withregister()which always returns results for all discovered skills. Callers have no way to know these skills were rejected without callinggetErrors().validator.jsskill.name = String(skill.name)mutates the caller's object. Side effect that could cause issues if the caller reuses the object.Medium
discoverer.js.agents/skills. If project-level skill is discovered first, user-level skill is silently dropped. Should check both directions.registry.jsreadFileSyncingetSkillBody()blocks the event loop. Acceptable for small files but could be problematic for large SKILL.md files.Low
discoverer.jsreaddirSync,statSync,existsSync,readFileSyncthroughout. Acceptable for skills directory (small scope) but worth noting for consistency.Clean Files
index.js— Re-exports only, no issuespermissions.js— Clean permission resolution logictypes.js— Clean Zod schemas, no issues