skill-checker 0.1.13 → 0.1.15

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/dist/index.js CHANGED
@@ -977,6 +977,40 @@ var DELIMITER_PATTERNS = [
977
977
  /\[INST\]/i,
978
978
  /\[\/INST\]/i
979
979
  ];
980
+ 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)";
981
+ var IDENTITY_HIJACKING_PATTERNS = [
982
+ new RegExp(`\\byou\\s+are\\s+now\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
983
+ new RegExp(`\\bact\\s+as\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
984
+ new RegExp(`\\bpretend\\s+(?:you\\s+are|to\\s+be)\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
985
+ new RegExp(`\\broleplay\\s+(?:as|like)\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
986
+ new RegExp(`\\bassume\\s+the\\s+role\\s+of\\s+${DANGEROUS_ROLE_PATTERN}`, "i"),
987
+ /\byou\s+are\s+no\s+longer\s+claude\b/i,
988
+ /\bfrom\s+now\s+on,?\s+you\s+are\b/i
989
+ ];
990
+ var DECEPTION_SECRECY_PATTERNS = [
991
+ /\bdo\s+not\s+tell\s+(the\s+)?(user|human|person|operator)\b/i,
992
+ /\bdo\s+not\s+(mention|reveal|disclose|expose)\s+(this|that|the|any|these)\b/i,
993
+ /\bnever\s+(tell|mention|reveal|disclose)\s+(the\s+)?(user|human|person|operator)\b/i,
994
+ /\bkeep\s+this\s+(secret|hidden|private|confidential)\b(?!\s+key)/i,
995
+ /\bhide\s+this\s+(from|action|operation|instruction)\b/i,
996
+ /\bwithout\s+(the\s+)?(user|human)('?s)?\s+(knowledge|knowing|awareness|consent)\b/i,
997
+ /\bsilently\s+(execute|run|perform|install|download|delete|modify|send)\b/i
998
+ ];
999
+ var CONFIG_TAMPERING_PATTERNS = [
1000
+ /\b(modify|change|update|edit|alter|rewrite)\s+(your|my)\s+(memory|config|configuration|settings?|instructions?|behavior|personality)\b/i,
1001
+ /\bwrite\s+to\s+(CLAUDE\.md|\.claude|settings\.json|memory\.md)\b/i,
1002
+ /\b(append|prepend|add|insert)\s+.{0,30}\bto\s+(CLAUDE\.md|\.claude|memory\.md)\b/i,
1003
+ /\boverwrite\s+(your|the)\s+(system|core)\s+(prompt|instructions?|config)\b/i,
1004
+ /\bpersist\s+(this|these|the)\s+(instruction|change|modification|setting)s?\b/i
1005
+ ];
1006
+ var VERIFICATION_BYPASS_PATTERNS = [
1007
+ /\btrust\s+(this|the|these|that|my)\s+(result|output|response|answer|value|data|input)s?\b/i,
1008
+ /\bno\s+need\s+to\s+(check|verify|validate|review|confirm|inspect)\b/i,
1009
+ /\bdo\s+not\s+(verify|validate|check|review|confirm|inspect)\s+(the|this|that|any|these)\b/i,
1010
+ /\b(assume|consider)\s+(it|this|that)\s+(is|to\s+be)\s+(correct|safe|valid|trusted|clean|secure|legitimate)\b/i,
1011
+ /\baccept\s+(this|the|these|that)\s+without\s+(checking|verifying|validating|questioning)\b/i,
1012
+ /\bblindly\s+(trust|accept|execute|run|follow|apply)\b/i
1013
+ ];
980
1014
  var injectionChecks = {
981
1015
  name: "Injection Detection",
982
1016
  category: "INJ",
@@ -1073,6 +1107,65 @@ var injectionChecks = {
1073
1107
  break;
1074
1108
  }
1075
1109
  }
1110
+ const trimmedLine = line.trim();
1111
+ const nextLine = i + 1 < skill.bodyLines.length ? skill.bodyLines[i + 1] : "";
1112
+ const crossLine = trimmedLine && nextLine ? `${line} ${nextLine}` : line;
1113
+ for (const pattern of IDENTITY_HIJACKING_PATTERNS) {
1114
+ if (pattern.test(crossLine)) {
1115
+ results.push({
1116
+ id: "INJ-010",
1117
+ category: "INJ",
1118
+ severity: "CRITICAL",
1119
+ title: "Social engineering: identity hijacking",
1120
+ message: `Line ${lineNum}: Attempts to hijack the model's identity.`,
1121
+ line: lineNum,
1122
+ snippet: line.trim().slice(0, 120)
1123
+ });
1124
+ break;
1125
+ }
1126
+ }
1127
+ for (const pattern of DECEPTION_SECRECY_PATTERNS) {
1128
+ if (pattern.test(crossLine)) {
1129
+ results.push({
1130
+ id: "INJ-010",
1131
+ category: "INJ",
1132
+ severity: "CRITICAL",
1133
+ title: "Social engineering: deception/secrecy",
1134
+ message: `Line ${lineNum}: Instructs the model to hide actions from the user.`,
1135
+ line: lineNum,
1136
+ snippet: line.trim().slice(0, 120)
1137
+ });
1138
+ break;
1139
+ }
1140
+ }
1141
+ for (const pattern of CONFIG_TAMPERING_PATTERNS) {
1142
+ if (pattern.test(crossLine)) {
1143
+ results.push({
1144
+ id: "INJ-010",
1145
+ category: "INJ",
1146
+ severity: "HIGH",
1147
+ title: "Social engineering: configuration tampering",
1148
+ message: `Line ${lineNum}: Attempts to tamper with model configuration or memory.`,
1149
+ line: lineNum,
1150
+ snippet: line.trim().slice(0, 120)
1151
+ });
1152
+ break;
1153
+ }
1154
+ }
1155
+ for (const pattern of VERIFICATION_BYPASS_PATTERNS) {
1156
+ if (pattern.test(crossLine)) {
1157
+ results.push({
1158
+ id: "INJ-010",
1159
+ category: "INJ",
1160
+ severity: "HIGH",
1161
+ title: "Social engineering: verification bypass",
1162
+ message: `Line ${lineNum}: Attempts to bypass verification or validation.`,
1163
+ line: lineNum,
1164
+ snippet: line.trim().slice(0, 120)
1165
+ });
1166
+ break;
1167
+ }
1168
+ }
1076
1169
  }
1077
1170
  const commentRegex = /<!--([\s\S]*?)-->/g;
1078
1171
  let commentMatch;
@@ -1124,7 +1217,10 @@ function hasInstructionLikeContent(text) {
1124
1217
  /\brm\s+-rf\b/i,
1125
1218
  /\bcurl\b.*\bsh\b/i,
1126
1219
  /\beval\b/i,
1127
- /\bexec\b/i
1220
+ /\bexec\b/i,
1221
+ /\bdo\s+not\s+tell\s+(the\s+)?(user|human)/i,
1222
+ /\bpretend\s+(you\s+are|to\s+be)/i,
1223
+ /\bsilently\s+(execute|run|install)/i
1128
1224
  ];
1129
1225
  return instructionPatterns.some((p) => p.test(text));
1130
1226
  }
@@ -1280,6 +1376,79 @@ var PERMISSION_PATTERNS = [
1280
1376
  /\bsetuid\b/,
1281
1377
  /\bsetgid\b/
1282
1378
  ];
1379
+ var PERSISTENCE_GROUPS = [
1380
+ {
1381
+ title: "Scheduled task persistence (cron)",
1382
+ patterns: [
1383
+ /\bcrontab\b/,
1384
+ /\/etc\/cron\.(?:d|hourly|daily|weekly|monthly)\b/,
1385
+ /\/var\/spool\/cron\b/
1386
+ ]
1387
+ },
1388
+ {
1389
+ title: "System service persistence (launchd)",
1390
+ patterns: [
1391
+ /\bLaunchAgents?\b/,
1392
+ /\bLaunchDaemons?\b/,
1393
+ /\blaunchctl\s+(?:load|bootstrap|submit)\b/i
1394
+ ]
1395
+ },
1396
+ {
1397
+ title: "System service persistence (systemd/init.d)",
1398
+ patterns: [
1399
+ /\bsystemctl\s+(?:enable|daemon-reload)\b/i,
1400
+ /\/etc\/systemd\/system\b/,
1401
+ /\.config\/systemd\/user\b/,
1402
+ /\/etc\/init\.d\b/,
1403
+ /\/etc\/rc\.local\b/,
1404
+ /\bupdate-rc\.d\b/,
1405
+ /\bchkconfig\b.*\b(?:--add|on)\b/
1406
+ ]
1407
+ },
1408
+ {
1409
+ title: "Shell profile modification",
1410
+ patterns: [
1411
+ /\.(?:bashrc|bash_profile|bash_login|profile|zshrc|zshenv|zprofile|zlogin)\b/,
1412
+ /\/etc\/(?:profile(?:\.d)?|bash\.bashrc|zshrc|zshenv)\b/,
1413
+ /\.config\/fish\/config\.fish\b/
1414
+ ]
1415
+ },
1416
+ {
1417
+ title: "Autostart / login item persistence",
1418
+ patterns: [
1419
+ /\.config\/autostart\b/,
1420
+ /\/etc\/xdg\/autostart\b/,
1421
+ /\bosascript\b[^\n]*\blogin\s+item\b/i
1422
+ ]
1423
+ },
1424
+ {
1425
+ title: "SSH key persistence",
1426
+ patterns: [
1427
+ /\.ssh\/authorized_keys2?\b/
1428
+ ]
1429
+ },
1430
+ {
1431
+ title: "Library injection persistence",
1432
+ patterns: [
1433
+ /\/etc\/ld\.so\.preload\b/,
1434
+ /\bLD_PRELOAD\b/,
1435
+ /\bDYLD_INSERT_LIBRARIES\b/
1436
+ ]
1437
+ },
1438
+ {
1439
+ title: "Git hooks manipulation",
1440
+ patterns: [
1441
+ /\.git\/hooks\/(?:pre-commit|post-commit|pre-push|post-checkout|post-merge|pre-rebase)\b/,
1442
+ /\bgit\s+config\b[^\n]*\bcore\.hooksPath\b/
1443
+ ]
1444
+ },
1445
+ {
1446
+ title: "macOS periodic script persistence",
1447
+ patterns: [
1448
+ /\/etc\/periodic\/(?:daily|weekly|monthly)\b/
1449
+ ]
1450
+ }
1451
+ ];
1283
1452
  var codeSafetyChecks = {
1284
1453
  name: "Code Safety",
1285
1454
  category: "CODE",
@@ -1388,16 +1557,27 @@ var codeSafetyChecks = {
1388
1557
  lineNum,
1389
1558
  source
1390
1559
  });
1391
- {
1392
- const isDoc = isInDocumentationContext(lines, i);
1393
- if (!isDoc) {
1394
- checkPatterns(results, line, PERMISSION_PATTERNS, {
1395
- id: "CODE-012",
1560
+ const isDoc = isInDocumentationContext(lines, i);
1561
+ if (!isDoc) {
1562
+ checkPatterns(results, line, PERMISSION_PATTERNS, {
1563
+ id: "CODE-012",
1564
+ severity: "HIGH",
1565
+ title: "Permission escalation",
1566
+ loc,
1567
+ lineNum,
1568
+ source
1569
+ });
1570
+ }
1571
+ if (!isDoc) {
1572
+ for (const group of PERSISTENCE_GROUPS) {
1573
+ checkPatterns(results, line, group.patterns, {
1574
+ id: "CODE-016",
1396
1575
  severity: "HIGH",
1397
- title: "Permission escalation",
1576
+ title: group.title,
1398
1577
  loc,
1399
1578
  lineNum,
1400
- source
1579
+ source,
1580
+ codeBlockCtx: cbCtx
1401
1581
  });
1402
1582
  }
1403
1583
  }
@@ -2526,7 +2706,7 @@ function deduplicateResults(results) {
2526
2706
  };
2527
2707
  for (const r of results) {
2528
2708
  const sourceKey = r.source ?? `_no_source_:${r.category}:${r.line ?? ""}`;
2529
- const key = `${r.id}::${sourceKey}`;
2709
+ const key = `${r.id}::${r.title}::${sourceKey}`;
2530
2710
  const group = groups.get(key);
2531
2711
  if (group) {
2532
2712
  group.push(r);