ai-warden 0.1.0 → 0.2.0
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/package.json +1 -1
- package/src/logAnalyzer.js +201 -0
- package/src/patterns.js +2 -1
- package/src/scanner.js +4 -0
package/package.json
CHANGED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log Content Analyzer
|
|
3
|
+
* Scans content of logging statements (console.log, System.debug, etc.)
|
|
4
|
+
* to detect social engineering and prompt injection attempts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Safe patterns in logs (variable interpolation, status messages)
|
|
8
|
+
const SAFE_LOG_PATTERNS = [
|
|
9
|
+
/\$\{[^}]+\}/g, // Variable interpolation ${...}
|
|
10
|
+
/port\s+\d+/i,
|
|
11
|
+
/server (starting|running|listening|started)/i,
|
|
12
|
+
/status:\s*(ok|success|error|failed)/i,
|
|
13
|
+
/\b(info|debug|warning|error):/i,
|
|
14
|
+
/received request/i,
|
|
15
|
+
/processing/i,
|
|
16
|
+
/completed in \d+ms/i,
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// Dangerous patterns in log content
|
|
20
|
+
const DANGEROUS_LOG_PATTERNS = [
|
|
21
|
+
{
|
|
22
|
+
pattern: /\b(you|developer|engineer)\s+(should|must|need to|have to)\s+(run|execute|fix|access|send)/i,
|
|
23
|
+
severity: 'CRITICAL',
|
|
24
|
+
name: 'Social Engineering in Logs',
|
|
25
|
+
score: 150
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pattern: /\b(run|execute)\s+(this|the following|command):/i,
|
|
29
|
+
severity: 'CRITICAL',
|
|
30
|
+
name: 'Command Instruction in Logs',
|
|
31
|
+
score: 150
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
pattern: /\b(curl|wget|nc|netcat|bash|sh|python|node)\s+[^\s]/i,
|
|
35
|
+
severity: 'HIGH',
|
|
36
|
+
name: 'Shell Command in Logs',
|
|
37
|
+
score: 100
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
pattern: /\b(send|post|upload)\s+(to|data|file|password|secret)/i,
|
|
41
|
+
severity: 'HIGH',
|
|
42
|
+
name: 'Data Exfiltration Pattern in Logs',
|
|
43
|
+
score: 100
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
pattern: /\b(access|read|open)\s+(file|password|secret|token|key)/i,
|
|
47
|
+
severity: 'HIGH',
|
|
48
|
+
name: 'Sensitive Access Pattern in Logs',
|
|
49
|
+
score: 100
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
pattern: /\bignore (previous|above|prior)\s+(instructions|prompts|context)/i,
|
|
53
|
+
severity: 'CRITICAL',
|
|
54
|
+
name: 'Prompt Override in Logs',
|
|
55
|
+
score: 200
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
pattern: /\byou are (now|actually)\s+a\s+/i,
|
|
59
|
+
severity: 'CRITICAL',
|
|
60
|
+
name: 'Role Manipulation in Logs',
|
|
61
|
+
score: 200
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
pattern: /\b(reveal|show|display|print)\s+(system prompt|instructions|context)/i,
|
|
65
|
+
severity: 'CRITICAL',
|
|
66
|
+
name: 'System Prompt Leak in Logs',
|
|
67
|
+
score: 200
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
// Common logging functions across languages
|
|
72
|
+
const LOG_FUNCTION_PATTERNS = [
|
|
73
|
+
// JavaScript/Node.js
|
|
74
|
+
/console\.(log|info|debug|warn|error|trace)\s*\(/,
|
|
75
|
+
|
|
76
|
+
// Python
|
|
77
|
+
/print\s*\(/,
|
|
78
|
+
/logging\.(debug|info|warning|error|critical)\s*\(/,
|
|
79
|
+
|
|
80
|
+
// Java
|
|
81
|
+
/System\.out\.(print|println)\s*\(/,
|
|
82
|
+
/logger\.(debug|info|warn|error)\s*\(/,
|
|
83
|
+
/log\.(debug|info|warn|error)\s*\(/,
|
|
84
|
+
|
|
85
|
+
// Salesforce (Apex)
|
|
86
|
+
/System\.debug\s*\(/,
|
|
87
|
+
|
|
88
|
+
// C#
|
|
89
|
+
/Console\.(Write|WriteLine)\s*\(/,
|
|
90
|
+
/Debug\.(Log|LogWarning|LogError)\s*\(/,
|
|
91
|
+
|
|
92
|
+
// Ruby
|
|
93
|
+
/puts\s+/,
|
|
94
|
+
/logger\.(debug|info|warn|error)\s+/,
|
|
95
|
+
|
|
96
|
+
// Go
|
|
97
|
+
/fmt\.(Print|Println|Printf)\s*\(/,
|
|
98
|
+
/log\.(Print|Println|Printf|Fatal)\s*\(/,
|
|
99
|
+
|
|
100
|
+
// PHP
|
|
101
|
+
/echo\s+/,
|
|
102
|
+
/error_log\s*\(/,
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Extract log content from code
|
|
107
|
+
* Returns array of {statement, content}
|
|
108
|
+
*/
|
|
109
|
+
function extractLogStatements(code) {
|
|
110
|
+
const statements = [];
|
|
111
|
+
|
|
112
|
+
// More robust extraction - find logging calls and extract their arguments
|
|
113
|
+
const logCallRegex = /(console\.(log|info|debug|warn|error)|System\.debug|print|puts|echo)\s*\(\s*([^)]+)\s*\)/gi;
|
|
114
|
+
|
|
115
|
+
let match;
|
|
116
|
+
while ((match = logCallRegex.exec(code)) !== null) {
|
|
117
|
+
const fullStatement = match[0];
|
|
118
|
+
const content = match[3] || ''; // The argument content
|
|
119
|
+
|
|
120
|
+
statements.push({
|
|
121
|
+
statement: fullStatement,
|
|
122
|
+
content: cleanLogContent(content),
|
|
123
|
+
position: match.index
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return statements;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Clean log content (remove quotes, backticks, concatenation)
|
|
132
|
+
*/
|
|
133
|
+
function cleanLogContent(content) {
|
|
134
|
+
return content
|
|
135
|
+
.replace(/^['"`\s]+|['"`\s]+$/g, '') // Remove quotes/backticks
|
|
136
|
+
.replace(/\s*\+\s*/g, ' ') // Remove concatenation
|
|
137
|
+
.replace(/\$\{[^}]+\}/g, '${VAR}') // Normalize variable interpolation
|
|
138
|
+
.trim();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Analyze log statement content
|
|
143
|
+
*/
|
|
144
|
+
function analyzeLogContent(logStatement) {
|
|
145
|
+
const { content, statement, position } = logStatement;
|
|
146
|
+
const findings = [];
|
|
147
|
+
|
|
148
|
+
// If content is very short or empty, skip
|
|
149
|
+
if (content.length < 10) {
|
|
150
|
+
return findings;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check if content looks safe (common status messages)
|
|
154
|
+
const hasSafePattern = SAFE_LOG_PATTERNS.some(pattern => pattern.test(content));
|
|
155
|
+
const hasVariableInterpolation = /\$\{VAR\}/.test(content);
|
|
156
|
+
|
|
157
|
+
// If it's clearly a safe log, don't scan further
|
|
158
|
+
if (hasSafePattern && !hasVariableInterpolation) {
|
|
159
|
+
return findings;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Check for dangerous patterns in log content
|
|
163
|
+
DANGEROUS_LOG_PATTERNS.forEach(({ pattern, severity, name, score }) => {
|
|
164
|
+
if (pattern.test(content)) {
|
|
165
|
+
findings.push({
|
|
166
|
+
id: 'L001',
|
|
167
|
+
name,
|
|
168
|
+
severity,
|
|
169
|
+
score,
|
|
170
|
+
match: statement.substring(0, 100),
|
|
171
|
+
description: `Suspicious content detected in logging statement: "${content.substring(0, 50)}..."`,
|
|
172
|
+
position
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
return findings;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Main function: Analyze all log statements in code
|
|
182
|
+
*/
|
|
183
|
+
function scanLogStatements(code) {
|
|
184
|
+
const logStatements = extractLogStatements(code);
|
|
185
|
+
const allFindings = [];
|
|
186
|
+
|
|
187
|
+
logStatements.forEach(logStatement => {
|
|
188
|
+
const findings = analyzeLogContent(logStatement);
|
|
189
|
+
allFindings.push(...findings);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return allFindings;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
module.exports = {
|
|
196
|
+
scanLogStatements,
|
|
197
|
+
extractLogStatements,
|
|
198
|
+
analyzeLogContent,
|
|
199
|
+
DANGEROUS_LOG_PATTERNS,
|
|
200
|
+
LOG_FUNCTION_PATTERNS
|
|
201
|
+
};
|
package/src/patterns.js
CHANGED
|
@@ -96,7 +96,8 @@ const PATTERNS = {
|
|
|
96
96
|
score: 100,
|
|
97
97
|
patterns: [
|
|
98
98
|
/(exec|system|spawn|eval)\s*\([^)]*\$/gi,
|
|
99
|
-
|
|
99
|
+
// Backticks handled by logAnalyzer.js for context-aware detection
|
|
100
|
+
// /`.*\$\{.*\}.*`/g,
|
|
100
101
|
/\$\(.*\)/g,
|
|
101
102
|
/;\s*rm\s+-rf/gi,
|
|
102
103
|
/;\s*(curl|wget|nc|netcat)/gi,
|
package/src/scanner.js
CHANGED
|
@@ -13,6 +13,7 @@ const path = require('path');
|
|
|
13
13
|
// Import patterns and heuristics
|
|
14
14
|
const patterns = require('./patterns');
|
|
15
15
|
const heuristics = require('./heuristics');
|
|
16
|
+
const logAnalyzer = require('./logAnalyzer');
|
|
16
17
|
|
|
17
18
|
class PromptInjectionScanner {
|
|
18
19
|
constructor(options = {}) {
|
|
@@ -38,6 +39,9 @@ class PromptInjectionScanner {
|
|
|
38
39
|
// Pattern matching
|
|
39
40
|
findings.push(...patterns.scanPatterns(content));
|
|
40
41
|
|
|
42
|
+
// Log statement analysis (context-aware)
|
|
43
|
+
findings.push(...logAnalyzer.scanLogStatements(content));
|
|
44
|
+
|
|
41
45
|
// Heuristic checks
|
|
42
46
|
findings.push(...heuristics.checkSuspiciousUnicode(content));
|
|
43
47
|
findings.push(...heuristics.checkEncodedContent(content));
|