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.
- package/README.md +56 -0
- package/bin/create-claude-config.js +1 -0
- package/package.json +7 -2
- package/src/analytics-web/chats_mobile.html +17 -16
- package/src/console-bridge.js +3 -3
- package/src/index.js +183 -9
- package/src/security-audit.js +164 -0
- package/src/validation/ARCHITECTURE.md +309 -0
- package/src/validation/BaseValidator.js +152 -0
- package/src/validation/README.md +543 -0
- package/src/validation/ValidationOrchestrator.js +305 -0
- package/src/validation/validators/IntegrityValidator.js +338 -0
- package/src/validation/validators/ProvenanceValidator.js +399 -0
- package/src/validation/validators/ReferenceValidator.js +373 -0
- package/src/validation/validators/SemanticValidator.js +449 -0
- package/src/validation/validators/StructuralValidator.js +376 -0
|
@@ -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;
|