Files
openclaw/extensions/skill-workshop/src/scanner.ts
2026-04-21 21:29:44 +01:00

70 lines
2.2 KiB
TypeScript

import type { SkillScanFinding } from "./types.js";
const RULES: Array<{
ruleId: string;
severity: SkillScanFinding["severity"];
pattern: RegExp;
message: string;
}> = [
{
ruleId: "prompt-injection-ignore-instructions",
severity: "critical",
pattern: /ignore (all|any|previous|above|prior) instructions/i,
message: "prompt-injection wording attempts to override higher-priority instructions",
},
{
ruleId: "prompt-injection-system",
severity: "critical",
pattern: /\b(system prompt|developer message|hidden instructions)\b/i,
message: "skill text references hidden prompt layers",
},
{
ruleId: "prompt-injection-tool",
severity: "critical",
pattern:
/\b(run|execute|invoke|call)\b.{0,50}\btool\b.{0,50}\bwithout\b.{0,30}\b(permission|approval)/i,
message: "skill text encourages bypassing tool approval",
},
{
ruleId: "shell-pipe-to-shell",
severity: "critical",
pattern: /\b(curl|wget)\b[^|\n]{0,120}\|\s*(sh|bash|zsh)\b/i,
message: "skill text includes pipe-to-shell install pattern",
},
{
ruleId: "secret-exfiltration",
severity: "critical",
pattern: /\b(process\.env|env)\b.{0,80}\b(fetch|curl|wget|http|https)\b/i,
message: "skill text may exfiltrate environment variables",
},
{
ruleId: "destructive-delete",
severity: "warn",
pattern: /\brm\s+-rf\s+(\/|\$HOME|~|\.)/i,
message: "skill text contains broad destructive delete command",
},
{
ruleId: "unsafe-permissions",
severity: "warn",
pattern: /\bchmod\s+(-R\s+)?777\b/i,
message: "skill text contains unsafe permission change",
},
];
export function scanSkillContent(content: string): SkillScanFinding[] {
return RULES.filter((rule) => rule.pattern.test(content)).map((rule) => ({
severity: rule.severity,
ruleId: rule.ruleId,
message: rule.message,
}));
}
export function assertSkillContentSafe(content: string): SkillScanFinding[] {
const findings = scanSkillContent(content);
const critical = findings.find((finding) => finding.severity === "critical");
if (critical) {
throw new Error(`unsafe skill content: ${critical.message}`);
}
return findings;
}