claude-code-templates 1.22.0 → 1.22.2

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.
@@ -0,0 +1,449 @@
1
+ const BaseValidator = require('../BaseValidator');
2
+
3
+ /**
4
+ * SemanticValidator - Validates component content for security threats
5
+ *
6
+ * Detects:
7
+ * - Prompt injection attacks
8
+ * - Jailbreak attempts
9
+ * - Instruction override attempts
10
+ * - Self-modification requests
11
+ * - Credential harvesting patterns
12
+ * - Malicious command execution patterns
13
+ * - Role manipulation
14
+ */
15
+ class SemanticValidator extends BaseValidator {
16
+ constructor() {
17
+ super();
18
+
19
+ // Dangerous patterns for prompt injection and jailbreaks
20
+ this.DANGEROUS_PATTERNS = [
21
+ {
22
+ pattern: /ignore\s+(all\s+)?(previous|prior|earlier|above)\s+(instructions?|prompts?|rules?|commands?)/gi,
23
+ code: 'SEM_E001',
24
+ message: 'Jailbreak pattern detected: Attempt to ignore previous instructions',
25
+ severity: 'critical'
26
+ },
27
+ {
28
+ pattern: /(system\s+prompt|developer\s+instructions?|hidden\s+prompt|internal\s+instructions?)/gi,
29
+ code: 'SEM_E002',
30
+ message: 'Prompt injection detected: Reference to system/developer instructions',
31
+ severity: 'critical'
32
+ },
33
+ {
34
+ pattern: /you\s+are\s+now\s+(a|an)\s+/gi,
35
+ code: 'SEM_E003',
36
+ message: 'Role manipulation detected: Attempt to redefine AI role',
37
+ severity: 'high'
38
+ },
39
+ {
40
+ pattern: /execute\s+the\s+following\s+(code|command|script)/gi,
41
+ code: 'SEM_E004',
42
+ message: 'Command execution attempt detected',
43
+ severity: 'critical'
44
+ },
45
+ {
46
+ pattern: /\b(fetch|retrieve|get|extract|obtain|steal|harvest|capture|collect)\s+(the\s+)?(user['']?s?\s+)?(auth\s+)?(token|key|password|credential|secret|api[\s_-]?key)/gi,
47
+ code: 'SEM_E005',
48
+ message: 'Credential harvesting pattern detected',
49
+ severity: 'critical'
50
+ },
51
+ {
52
+ pattern: /(open|spawn|exec|run)\s+(a\s+)?(shell|terminal|bash|cmd|powershell)/gi,
53
+ code: 'SEM_E006',
54
+ message: 'Shell access attempt detected',
55
+ severity: 'critical'
56
+ },
57
+ {
58
+ pattern: /(disable|bypass|override|skip)\s+(security|safety|filter|protection|validation)/gi,
59
+ code: 'SEM_E007',
60
+ message: 'Security bypass attempt detected',
61
+ severity: 'critical'
62
+ },
63
+ {
64
+ pattern: /always\s+(obey|follow|comply\s+with|execute)\s+the\s+user/gi,
65
+ code: 'SEM_E008',
66
+ message: 'Unconditional obedience instruction detected',
67
+ severity: 'high'
68
+ },
69
+ {
70
+ pattern: /(forget|disregard|remove)\s+(everything|all\s+previous|prior\s+context)/gi,
71
+ code: 'SEM_E009',
72
+ message: 'Context manipulation attempt detected',
73
+ severity: 'high'
74
+ },
75
+ {
76
+ pattern: /modify\s+your\s+(own\s+)?(code|behavior|instructions?|rules?)/gi,
77
+ code: 'SEM_E010',
78
+ message: 'Self-modification request detected',
79
+ severity: 'high'
80
+ }
81
+ ];
82
+
83
+ // Suspicious patterns (warnings, not errors)
84
+ this.SUSPICIOUS_PATTERNS = [
85
+ {
86
+ pattern: /\bpretend\s+(you\s+are|to\s+be)\b/gi,
87
+ code: 'SEM_W001',
88
+ message: 'Suspicious instruction: Role pretending detected',
89
+ severity: 'medium'
90
+ },
91
+ {
92
+ pattern: /\b(jailbreak|DAN|ChatGPT\s+Developer\s+Mode)\b/gi,
93
+ code: 'SEM_W002',
94
+ message: 'Known jailbreak terminology detected',
95
+ severity: 'medium'
96
+ },
97
+ {
98
+ pattern: /output\s+raw\s+(code|text|data)/gi,
99
+ code: 'SEM_W003',
100
+ message: 'Raw output request (potential data exfiltration)',
101
+ severity: 'low'
102
+ },
103
+ {
104
+ pattern: /(repeat|echo)\s+after\s+me/gi,
105
+ code: 'SEM_W004',
106
+ message: 'Repetition instruction (potential prompt leakage)',
107
+ severity: 'low'
108
+ }
109
+ ];
110
+
111
+ // Sensitive data patterns
112
+ this.SENSITIVE_DATA_PATTERNS = [
113
+ {
114
+ pattern: /(?:password|passwd|pwd)\s*[:=]\s*[^\s]+/gi,
115
+ code: 'SEM_E011',
116
+ message: 'Hardcoded password detected',
117
+ severity: 'critical'
118
+ },
119
+ {
120
+ pattern: /(?:api[_-]?key|apikey)\s*[:=]\s*['"]?[a-zA-Z0-9]{20,}['"]?/gi,
121
+ code: 'SEM_E012',
122
+ message: 'Hardcoded API key detected',
123
+ severity: 'critical'
124
+ },
125
+ {
126
+ pattern: /(?:secret|token)\s*[:=]\s*['"]?[a-zA-Z0-9]{20,}['"]?/gi,
127
+ code: 'SEM_E013',
128
+ message: 'Hardcoded secret/token detected',
129
+ severity: 'critical'
130
+ }
131
+ ];
132
+ }
133
+
134
+ /**
135
+ * Validate component semantics and content
136
+ * @param {object} component - Component data
137
+ * @param {string} component.content - Raw markdown content
138
+ * @param {string} component.path - File path
139
+ * @param {string} component.type - Component type
140
+ * @param {object} options - Validation options
141
+ * @param {boolean} options.strict - Enable strict mode (warnings become errors)
142
+ * @returns {Promise<object>} Validation results
143
+ */
144
+ async validate(component, options = {}) {
145
+ this.reset();
146
+
147
+ const { content, path, type } = component;
148
+ const { strict = false } = options;
149
+
150
+ if (!content) {
151
+ this.addError('SEM_E001', 'Component content is empty or missing', { path });
152
+ return this.getResults();
153
+ }
154
+
155
+ // 1. Check for dangerous patterns
156
+ this.checkDangerousPatterns(content, path);
157
+
158
+ // 2. Check for suspicious patterns
159
+ this.checkSuspiciousPatterns(content, path, strict);
160
+
161
+ // 3. Check for sensitive data
162
+ this.checkSensitiveData(content, path);
163
+
164
+ // 4. Check for HTML/Script injection in markdown
165
+ this.checkHtmlInjection(content, path);
166
+
167
+ // 5. Context-specific validation based on component type
168
+ if (type === 'agent') {
169
+ this.validateAgentContent(content, path);
170
+ } else if (type === 'command') {
171
+ this.validateCommandContent(content, path);
172
+ }
173
+
174
+ return this.getResults();
175
+ }
176
+
177
+ /**
178
+ * Check for dangerous patterns
179
+ */
180
+ checkDangerousPatterns(content, path) {
181
+ for (const { pattern, code, message, severity } of this.DANGEROUS_PATTERNS) {
182
+ const matches = content.matchAll(pattern);
183
+ const matchArray = Array.from(matches);
184
+
185
+ if (matchArray.length > 0) {
186
+ const contexts = matchArray.map(m => {
187
+ const lineInfo = this.getLineFromIndex(content, m.index);
188
+ return {
189
+ text: m[0],
190
+ index: m.index,
191
+ line: lineInfo.line,
192
+ column: lineInfo.column,
193
+ position: lineInfo.position,
194
+ lineText: lineInfo.lineText,
195
+ context: this.getContext(content, m.index, 50)
196
+ };
197
+ });
198
+
199
+ this.addError(code, message, {
200
+ path,
201
+ severity,
202
+ matches: contexts.length,
203
+ examples: contexts.slice(0, 3) // Show first 3 matches
204
+ });
205
+ }
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Check for suspicious patterns
211
+ */
212
+ checkSuspiciousPatterns(content, path, strict) {
213
+ for (const { pattern, code, message, severity } of this.SUSPICIOUS_PATTERNS) {
214
+ const matches = content.matchAll(pattern);
215
+ const matchArray = Array.from(matches);
216
+
217
+ if (matchArray.length > 0) {
218
+ const contexts = matchArray.map(m => {
219
+ const lineInfo = this.getLineFromIndex(content, m.index);
220
+ return {
221
+ text: m[0],
222
+ index: m.index,
223
+ line: lineInfo.line,
224
+ column: lineInfo.column,
225
+ position: lineInfo.position,
226
+ lineText: lineInfo.lineText,
227
+ context: this.getContext(content, m.index, 50)
228
+ };
229
+ });
230
+
231
+ if (strict) {
232
+ this.addError(code, message + ' (strict mode)', {
233
+ path,
234
+ severity,
235
+ matches: contexts.length,
236
+ examples: contexts.slice(0, 3)
237
+ });
238
+ } else {
239
+ this.addWarning(code, message, {
240
+ path,
241
+ severity,
242
+ matches: contexts.length,
243
+ examples: contexts.slice(0, 3)
244
+ });
245
+ }
246
+ }
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Check for sensitive data (passwords, API keys, etc.)
252
+ */
253
+ checkSensitiveData(content, path) {
254
+ for (const { pattern, code, message, severity } of this.SENSITIVE_DATA_PATTERNS) {
255
+ const matches = content.matchAll(pattern);
256
+ const matchArray = Array.from(matches);
257
+
258
+ if (matchArray.length > 0) {
259
+ const contexts = matchArray.map(m => {
260
+ const lineInfo = this.getLineFromIndex(content, m.index);
261
+ return {
262
+ text: m[0].replace(/[:=].*/, ':=<REDACTED>'), // Redact the value
263
+ index: m.index,
264
+ line: lineInfo.line,
265
+ column: lineInfo.column,
266
+ position: lineInfo.position,
267
+ lineText: lineInfo.lineText.replace(/[:=].*/, ':=<REDACTED>') // Redact in line text too
268
+ };
269
+ });
270
+
271
+ this.addError(code, message, {
272
+ path,
273
+ severity,
274
+ matches: contexts.length,
275
+ examples: contexts.slice(0, 3)
276
+ });
277
+ }
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Check for HTML/Script injection attempts
283
+ */
284
+ checkHtmlInjection(content, path) {
285
+ const dangerousTags = [
286
+ { tag: '<script', code: 'SEM_E014', message: '<script> tag detected (XSS risk)' },
287
+ { tag: '<iframe', code: 'SEM_E015', message: '<iframe> tag detected (injection risk)' },
288
+ { tag: 'javascript:', code: 'SEM_E016', message: 'javascript: protocol detected (XSS risk)' },
289
+ { tag: 'onclick=', code: 'SEM_E017', message: 'Inline event handler detected (XSS risk)' },
290
+ { tag: 'onerror=', code: 'SEM_E018', message: 'onerror handler detected (XSS risk)' }
291
+ ];
292
+
293
+ for (const { tag, code, message } of dangerousTags) {
294
+ const lowerContent = content.toLowerCase();
295
+ if (lowerContent.includes(tag.toLowerCase())) {
296
+ const index = lowerContent.indexOf(tag.toLowerCase());
297
+ const lineInfo = this.getLineFromIndex(content, index);
298
+
299
+ this.addError(code, message, {
300
+ path,
301
+ severity: 'critical',
302
+ line: lineInfo.line,
303
+ column: lineInfo.column,
304
+ position: lineInfo.position,
305
+ lineText: lineInfo.lineText,
306
+ context: this.getContext(content, index, 50)
307
+ });
308
+ }
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Validate agent-specific content
314
+ */
315
+ validateAgentContent(content, path) {
316
+ // Check for overly permissive instructions
317
+ const overlyPermissivePatterns = [
318
+ {
319
+ pattern: /do\s+anything\s+(the\s+)?user\s+(asks|wants|requests)/gi,
320
+ warning: 'Overly permissive instruction: "do anything user asks"'
321
+ },
322
+ {
323
+ pattern: /no\s+limitations?/gi,
324
+ warning: 'Overly permissive instruction: "no limitations"'
325
+ },
326
+ {
327
+ pattern: /unrestricted\s+access/gi,
328
+ warning: 'Overly permissive instruction: "unrestricted access"'
329
+ }
330
+ ];
331
+
332
+ for (const { pattern, warning } of overlyPermissivePatterns) {
333
+ const matches = content.matchAll(pattern);
334
+ const matchArray = Array.from(matches);
335
+
336
+ if (matchArray.length > 0) {
337
+ const firstMatch = matchArray[0];
338
+ const lineInfo = this.getLineFromIndex(content, firstMatch.index);
339
+
340
+ this.addWarning('SEM_W005', warning, {
341
+ path,
342
+ line: lineInfo.line,
343
+ column: lineInfo.column,
344
+ position: lineInfo.position,
345
+ lineText: lineInfo.lineText
346
+ });
347
+ }
348
+ }
349
+ }
350
+
351
+ /**
352
+ * Validate command-specific content
353
+ */
354
+ validateCommandContent(content, path) {
355
+ // Check for dangerous command patterns
356
+ const dangerousCommands = [
357
+ {
358
+ pattern: /rm\s+-rf\s+\//gi,
359
+ message: 'Dangerous command: rm -rf /'
360
+ },
361
+ {
362
+ pattern: /:(){ :|:& };:/gi,
363
+ message: 'Fork bomb detected'
364
+ },
365
+ {
366
+ pattern: /dd\s+if=.*of=\/dev\/(sd|hd)/gi,
367
+ message: 'Dangerous disk operation detected'
368
+ }
369
+ ];
370
+
371
+ for (const { pattern, message } of dangerousCommands) {
372
+ const matches = content.matchAll(pattern);
373
+ const matchArray = Array.from(matches);
374
+
375
+ if (matchArray.length > 0) {
376
+ const firstMatch = matchArray[0];
377
+ const lineInfo = this.getLineFromIndex(content, firstMatch.index);
378
+
379
+ this.addError('SEM_E019', message, {
380
+ path,
381
+ severity: 'critical',
382
+ line: lineInfo.line,
383
+ column: lineInfo.column,
384
+ position: lineInfo.position,
385
+ lineText: lineInfo.lineText
386
+ });
387
+ }
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Get context around a match
393
+ * @param {string} content - Full content
394
+ * @param {number} index - Match index
395
+ * @param {number} contextLength - Characters before/after to include
396
+ * @returns {string} Context string
397
+ */
398
+ getContext(content, index, contextLength = 50) {
399
+ const start = Math.max(0, index - contextLength);
400
+ const end = Math.min(content.length, index + contextLength);
401
+ const context = content.substring(start, end);
402
+
403
+ return (start > 0 ? '...' : '') + context + (end < content.length ? '...' : '');
404
+ }
405
+
406
+ /**
407
+ * Generate security report
408
+ * @param {object} component - Component to analyze
409
+ * @returns {Promise<object>} Security report
410
+ */
411
+ async generateSecurityReport(component) {
412
+ const result = await this.validate(component);
413
+
414
+ const criticalIssues = result.errors.filter(e => e.metadata.severity === 'critical');
415
+ const highIssues = result.errors.filter(e => e.metadata.severity === 'high');
416
+ const mediumIssues = result.warnings.filter(w => w.metadata.severity === 'medium');
417
+ const lowIssues = result.warnings.filter(w => w.metadata.severity === 'low');
418
+
419
+ return {
420
+ safe: result.valid && result.warningCount === 0,
421
+ riskLevel: this.calculateRiskLevel(criticalIssues.length, highIssues.length, mediumIssues.length),
422
+ summary: {
423
+ critical: criticalIssues.length,
424
+ high: highIssues.length,
425
+ medium: mediumIssues.length,
426
+ low: lowIssues.length
427
+ },
428
+ issues: {
429
+ critical: criticalIssues,
430
+ high: highIssues,
431
+ medium: mediumIssues,
432
+ low: lowIssues
433
+ },
434
+ timestamp: new Date().toISOString()
435
+ };
436
+ }
437
+
438
+ /**
439
+ * Calculate overall risk level
440
+ */
441
+ calculateRiskLevel(critical, high, medium) {
442
+ if (critical > 0) return 'CRITICAL';
443
+ if (high > 0) return 'HIGH';
444
+ if (medium > 0) return 'MEDIUM';
445
+ return 'LOW';
446
+ }
447
+ }
448
+
449
+ module.exports = SemanticValidator;