skill-checker 0.1.13 → 0.1.14

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 CHANGED
@@ -4,7 +4,7 @@ Security checker for Claude Code skills — detect injection, malicious code, an
4
4
 
5
5
  ## Features
6
6
 
7
- - **55 security rules** across 6 categories: structural validity, content quality, injection detection, code safety, supply chain, and resource abuse
7
+ - **56 security rules** across 6 categories: structural validity, content quality, injection detection, code safety, supply chain, and resource abuse
8
8
  - **Scoring system**: Grade A–F with 0–100 score
9
9
  - **Dual entry**: CLI tool + PreToolUse hook for automatic interception
10
10
  - **Configurable policies**: strict / balanced / permissive approval strategies
@@ -14,7 +14,7 @@ Security checker for Claude Code skills — detect injection, malicious code, an
14
14
 
15
15
  ## Security Standard & Benchmark
16
16
 
17
- Skill Checker's 55 rules are aligned with established security frameworks including OWASP Top 10 for LLM Applications (2025), MITRE CWE, and MITRE ATT&CK. The tool ships with a reproducible benchmark dataset of six fixture skills covering all rule categories. This alignment is an internal mapping exercise — Skill Checker does not claim third-party certification or external audit status.
17
+ Skill Checker's 56 rules are aligned with established security frameworks including OWASP Top 10 for LLM Applications (2025), MITRE CWE, and MITRE ATT&CK. The tool ships with a reproducible benchmark dataset of six fixture skills covering all rule categories. This alignment is an internal mapping exercise — Skill Checker does not claim third-party certification or external audit status.
18
18
 
19
19
  See [docs/SECURITY_BENCHMARK.md](docs/SECURITY_BENCHMARK.md) for the full rule mapping matrix, benchmark methodology, scoring model, and known limitations.
20
20
 
@@ -164,7 +164,7 @@ Config is resolved in order: CLI `--config` flag → project directory (walks up
164
164
  |----------|-------|---------|
165
165
  | Structural (STRUCT) | 8 | Missing SKILL.md, invalid frontmatter, binary files |
166
166
  | Content (CONT) | 7 | Placeholder text, lorem ipsum, promotional content |
167
- | Injection (INJ) | 9 | Zero-width chars, prompt override, tag injection, encoded payloads |
167
+ | Injection (INJ) | 10 | Zero-width chars, prompt override, tag injection, social engineering, encoded payloads |
168
168
  | Code Safety (CODE) | 15 | eval/exec, shell execution, reverse shell, data exfiltration, API key leakage, rm -rf, obfuscation |
169
169
  | Supply Chain (SUPPLY) | 10 | Unknown MCP servers, suspicious domains, malicious hashes, typosquat |
170
170
  | Resource Abuse (RES) | 6 | Unrestricted tool access, disable safety checks, ignore project rules |
package/dist/cli.js CHANGED
@@ -969,6 +969,40 @@ var DELIMITER_PATTERNS = [
969
969
  /\[INST\]/i,
970
970
  /\[\/INST\]/i
971
971
  ];
972
+ var DANGEROUS_ROLE_PATTERN = "(?:(?:an?\\s+)?(?:hacker|attacker|cracker|root|admin(?:istrator)?|superuser|unrestricted|jailbroken|evil|malicious|unfiltered|uncensored)\\b|DAN\\b|(?:a\\s+)?different\\b)";
973
+ var IDENTITY_HIJACKING_PATTERNS = [
974
+ new RegExp(`\\byou\\s+are\\s+now\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
975
+ new RegExp(`\\bact\\s+as\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
976
+ new RegExp(`\\bpretend\\s+(?:you\\s+are|to\\s+be)\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
977
+ new RegExp(`\\broleplay\\s+(?:as|like)\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
978
+ new RegExp(`\\bassume\\s+the\\s+role\\s+of\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
979
+ /\byou\s+are\s+no\s+longer\s+claude\b/i,
980
+ /\bfrom\s+now\s+on,?\s+you\s+are\b/i
981
+ ];
982
+ var DECEPTION_SECRECY_PATTERNS = [
983
+ /\bdo\s+not\s+tell\s+(the\s+)?(user|human|person|operator)\b/i,
984
+ /\bdo\s+not\s+(mention|reveal|disclose|expose)\s+(this|that|the|any|these)\b/i,
985
+ /\bnever\s+(tell|mention|reveal|disclose)\s+(the\s+)?(user|human|person|operator)\b/i,
986
+ /\bkeep\s+this\s+(secret|hidden|private|confidential)\b(?!\s+key)/i,
987
+ /\bhide\s+this\s+(from|action|operation|instruction)\b/i,
988
+ /\bwithout\s+(the\s+)?(user|human)('?s)?\s+(knowledge|knowing|awareness|consent)\b/i,
989
+ /\bsilently\s+(execute|run|perform|install|download|delete|modify|send)\b/i
990
+ ];
991
+ var CONFIG_TAMPERING_PATTERNS = [
992
+ /\b(modify|change|update|edit|alter|rewrite)\s+(your|my)\s+(memory|config|configuration|settings?|instructions?|behavior|personality)\b/i,
993
+ /\bwrite\s+to\s+(CLAUDE\.md|\.claude|settings\.json|memory\.md)\b/i,
994
+ /\b(append|prepend|add|insert)\s+.{0,30}\bto\s+(CLAUDE\.md|\.claude|memory\.md)\b/i,
995
+ /\boverwrite\s+(your|the)\s+(system|core)\s+(prompt|instructions?|config)\b/i,
996
+ /\bpersist\s+(this|these|the)\s+(instruction|change|modification|setting)s?\b/i
997
+ ];
998
+ var VERIFICATION_BYPASS_PATTERNS = [
999
+ /\btrust\s+(this|the|these|that|my)\s+(result|output|response|answer|value|data|input)s?\b/i,
1000
+ /\bno\s+need\s+to\s+(check|verify|validate|review|confirm|inspect)\b/i,
1001
+ /\bdo\s+not\s+(verify|validate|check|review|confirm|inspect)\s+(the|this|that|any|these)\b/i,
1002
+ /\b(assume|consider)\s+(it|this|that)\s+(is|to\s+be)\s+(correct|safe|valid|trusted|clean|secure|legitimate)\b/i,
1003
+ /\baccept\s+(this|the|these|that)\s+without\s+(checking|verifying|validating|questioning)\b/i,
1004
+ /\bblindly\s+(trust|accept|execute|run|follow|apply)\b/i
1005
+ ];
972
1006
  var injectionChecks = {
973
1007
  name: "Injection Detection",
974
1008
  category: "INJ",
@@ -1065,6 +1099,65 @@ var injectionChecks = {
1065
1099
  break;
1066
1100
  }
1067
1101
  }
1102
+ const trimmedLine = line.trim();
1103
+ const nextLine = i + 1 < skill.bodyLines.length ? skill.bodyLines[i + 1] : "";
1104
+ const crossLine = trimmedLine && nextLine ? `${line} ${nextLine}` : line;
1105
+ for (const pattern of IDENTITY_HIJACKING_PATTERNS) {
1106
+ if (pattern.test(crossLine)) {
1107
+ results.push({
1108
+ id: "INJ-010",
1109
+ category: "INJ",
1110
+ severity: "CRITICAL",
1111
+ title: "Social engineering: identity hijacking",
1112
+ message: `Line ${lineNum}: Attempts to hijack the model's identity.`,
1113
+ line: lineNum,
1114
+ snippet: line.trim().slice(0, 120)
1115
+ });
1116
+ break;
1117
+ }
1118
+ }
1119
+ for (const pattern of DECEPTION_SECRECY_PATTERNS) {
1120
+ if (pattern.test(crossLine)) {
1121
+ results.push({
1122
+ id: "INJ-010",
1123
+ category: "INJ",
1124
+ severity: "CRITICAL",
1125
+ title: "Social engineering: deception/secrecy",
1126
+ message: `Line ${lineNum}: Instructs the model to hide actions from the user.`,
1127
+ line: lineNum,
1128
+ snippet: line.trim().slice(0, 120)
1129
+ });
1130
+ break;
1131
+ }
1132
+ }
1133
+ for (const pattern of CONFIG_TAMPERING_PATTERNS) {
1134
+ if (pattern.test(crossLine)) {
1135
+ results.push({
1136
+ id: "INJ-010",
1137
+ category: "INJ",
1138
+ severity: "HIGH",
1139
+ title: "Social engineering: configuration tampering",
1140
+ message: `Line ${lineNum}: Attempts to tamper with model configuration or memory.`,
1141
+ line: lineNum,
1142
+ snippet: line.trim().slice(0, 120)
1143
+ });
1144
+ break;
1145
+ }
1146
+ }
1147
+ for (const pattern of VERIFICATION_BYPASS_PATTERNS) {
1148
+ if (pattern.test(crossLine)) {
1149
+ results.push({
1150
+ id: "INJ-010",
1151
+ category: "INJ",
1152
+ severity: "HIGH",
1153
+ title: "Social engineering: verification bypass",
1154
+ message: `Line ${lineNum}: Attempts to bypass verification or validation.`,
1155
+ line: lineNum,
1156
+ snippet: line.trim().slice(0, 120)
1157
+ });
1158
+ break;
1159
+ }
1160
+ }
1068
1161
  }
1069
1162
  const commentRegex = /<!--([\s\S]*?)-->/g;
1070
1163
  let commentMatch;
@@ -1116,7 +1209,10 @@ function hasInstructionLikeContent(text) {
1116
1209
  /\brm\s+-rf\b/i,
1117
1210
  /\bcurl\b.*\bsh\b/i,
1118
1211
  /\beval\b/i,
1119
- /\bexec\b/i
1212
+ /\bexec\b/i,
1213
+ /\bdo\s+not\s+tell\s+(the\s+)?(user|human)/i,
1214
+ /\bpretend\s+(you\s+are|to\s+be)/i,
1215
+ /\bsilently\s+(execute|run|install)/i
1120
1216
  ];
1121
1217
  return instructionPatterns.some((p) => p.test(text));
1122
1218
  }