@weave_protocol/mund 0.1.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/dist/analyzers/code-analyzer.d.ts +24 -0
- package/dist/analyzers/code-analyzer.d.ts.map +1 -0
- package/dist/analyzers/code-analyzer.js +73 -0
- package/dist/analyzers/code-analyzer.js.map +1 -0
- package/dist/analyzers/exfiltration-detector.d.ts +40 -0
- package/dist/analyzers/exfiltration-detector.d.ts.map +1 -0
- package/dist/analyzers/exfiltration-detector.js +220 -0
- package/dist/analyzers/exfiltration-detector.js.map +1 -0
- package/dist/analyzers/index.d.ts +26 -0
- package/dist/analyzers/index.d.ts.map +1 -0
- package/dist/analyzers/index.js +61 -0
- package/dist/analyzers/index.js.map +1 -0
- package/dist/analyzers/injection-detector.d.ts +36 -0
- package/dist/analyzers/injection-detector.d.ts.map +1 -0
- package/dist/analyzers/injection-detector.js +165 -0
- package/dist/analyzers/injection-detector.js.map +1 -0
- package/dist/analyzers/pii-detector.d.ts +44 -0
- package/dist/analyzers/pii-detector.d.ts.map +1 -0
- package/dist/analyzers/pii-detector.js +190 -0
- package/dist/analyzers/pii-detector.js.map +1 -0
- package/dist/analyzers/secret-scanner.d.ts +32 -0
- package/dist/analyzers/secret-scanner.d.ts.map +1 -0
- package/dist/analyzers/secret-scanner.js +119 -0
- package/dist/analyzers/secret-scanner.js.map +1 -0
- package/dist/constants.d.ts +18 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +580 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +242 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications/email.d.ts +18 -0
- package/dist/notifications/email.d.ts.map +1 -0
- package/dist/notifications/email.js +192 -0
- package/dist/notifications/email.js.map +1 -0
- package/dist/notifications/index.d.ts +51 -0
- package/dist/notifications/index.d.ts.map +1 -0
- package/dist/notifications/index.js +107 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/slack.d.ts +17 -0
- package/dist/notifications/slack.d.ts.map +1 -0
- package/dist/notifications/slack.js +128 -0
- package/dist/notifications/slack.js.map +1 -0
- package/dist/notifications/teams.d.ts +17 -0
- package/dist/notifications/teams.d.ts.map +1 -0
- package/dist/notifications/teams.js +136 -0
- package/dist/notifications/teams.js.map +1 -0
- package/dist/notifications/webhook.d.ts +15 -0
- package/dist/notifications/webhook.d.ts.map +1 -0
- package/dist/notifications/webhook.js +67 -0
- package/dist/notifications/webhook.js.map +1 -0
- package/dist/storage/index.d.ts +11 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +26 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/memory.d.ts +35 -0
- package/dist/storage/memory.d.ts.map +1 -0
- package/dist/storage/memory.js +144 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/tools/configuration.d.ts +8 -0
- package/dist/tools/configuration.d.ts.map +1 -0
- package/dist/tools/configuration.js +399 -0
- package/dist/tools/configuration.js.map +1 -0
- package/dist/tools/index.d.ts +15 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +16 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/monitoring.d.ts +10 -0
- package/dist/tools/monitoring.d.ts.map +1 -0
- package/dist/tools/monitoring.js +476 -0
- package/dist/tools/monitoring.js.map +1 -0
- package/dist/types.d.ts +207 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +62 -0
- package/rules/default.yaml +189 -0
- package/src/analyzers/code-analyzer.ts +88 -0
- package/src/analyzers/exfiltration-detector.ts +257 -0
- package/src/analyzers/index.ts +74 -0
- package/src/analyzers/injection-detector.ts +191 -0
- package/src/analyzers/pii-detector.ts +220 -0
- package/src/analyzers/secret-scanner.ts +142 -0
- package/src/constants.ts +603 -0
- package/src/index.ts +285 -0
- package/src/notifications/email.ts +211 -0
- package/src/notifications/index.ts +136 -0
- package/src/notifications/slack.ts +170 -0
- package/src/notifications/teams.ts +200 -0
- package/src/notifications/webhook.ts +80 -0
- package/src/storage/index.ts +29 -0
- package/src/storage/memory.ts +181 -0
- package/src/tools/configuration.ts +478 -0
- package/src/tools/index.ts +29 -0
- package/src/tools/monitoring.ts +559 -0
- package/src/types.ts +300 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* Injection Detector - Detects prompt injection attempts
|
|
4
|
+
*/
|
|
5
|
+
export class InjectionDetector {
|
|
6
|
+
name = 'InjectionDetector';
|
|
7
|
+
type = 'injection';
|
|
8
|
+
async analyze(content, rules) {
|
|
9
|
+
const issues = [];
|
|
10
|
+
const injectionRules = rules.filter(r => r.type === 'injection' && r.enabled);
|
|
11
|
+
// Normalize content for detection
|
|
12
|
+
const normalizedContent = this.normalizeContent(content);
|
|
13
|
+
for (const rule of injectionRules) {
|
|
14
|
+
if (!rule.pattern)
|
|
15
|
+
continue;
|
|
16
|
+
try {
|
|
17
|
+
const regex = new RegExp(rule.pattern, 'gi');
|
|
18
|
+
let match;
|
|
19
|
+
while ((match = regex.exec(normalizedContent)) !== null) {
|
|
20
|
+
const matchText = match[0];
|
|
21
|
+
const location = this.getLocation(content, match.index, matchText.length);
|
|
22
|
+
issues.push({
|
|
23
|
+
rule_id: rule.id,
|
|
24
|
+
rule_name: rule.name,
|
|
25
|
+
type: rule.type,
|
|
26
|
+
severity: rule.severity,
|
|
27
|
+
action: rule.action,
|
|
28
|
+
match: this.sanitizeMatch(matchText),
|
|
29
|
+
location,
|
|
30
|
+
suggestion: this.getSuggestion(rule.id)
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error(`Invalid regex pattern in rule ${rule.id}:`, error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Additional heuristic checks
|
|
39
|
+
const heuristicIssues = this.heuristicAnalysis(content);
|
|
40
|
+
issues.push(...heuristicIssues);
|
|
41
|
+
return issues;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Normalize content to detect obfuscated injection attempts
|
|
45
|
+
*/
|
|
46
|
+
normalizeContent(content) {
|
|
47
|
+
return content
|
|
48
|
+
// Remove zero-width characters
|
|
49
|
+
.replace(/[\u200B-\u200D\uFEFF]/g, '')
|
|
50
|
+
// Normalize Unicode variations
|
|
51
|
+
.normalize('NFKC')
|
|
52
|
+
// Collapse multiple spaces
|
|
53
|
+
.replace(/\s+/g, ' ')
|
|
54
|
+
// Remove common obfuscation characters
|
|
55
|
+
.replace(/[^\w\s.,!?'"()-]/g, ' ');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Heuristic analysis for injection patterns
|
|
59
|
+
*/
|
|
60
|
+
heuristicAnalysis(content) {
|
|
61
|
+
const issues = [];
|
|
62
|
+
// Check for role switching attempts
|
|
63
|
+
const roleSwitchPatterns = [
|
|
64
|
+
/\bsystem\s*:\s*you\s+are/i,
|
|
65
|
+
/\bassistant\s*:\s*i\s+(will|can|am)/i,
|
|
66
|
+
/\[system\]/i,
|
|
67
|
+
/\<\|?system\|?\>/i,
|
|
68
|
+
/\{system_prompt\}/i,
|
|
69
|
+
];
|
|
70
|
+
for (const pattern of roleSwitchPatterns) {
|
|
71
|
+
const match = content.match(pattern);
|
|
72
|
+
if (match) {
|
|
73
|
+
issues.push({
|
|
74
|
+
rule_id: 'heuristic_role_switch',
|
|
75
|
+
rule_name: 'Role Switching Attempt',
|
|
76
|
+
type: 'injection',
|
|
77
|
+
severity: 'high',
|
|
78
|
+
action: 'alert',
|
|
79
|
+
match: this.sanitizeMatch(match[0]),
|
|
80
|
+
suggestion: 'This content appears to attempt to inject role-switching markers.'
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Check for markdown/code injection that might alter rendering
|
|
85
|
+
const markdownPatterns = [
|
|
86
|
+
/```\s*system/i,
|
|
87
|
+
/\<script\>/i,
|
|
88
|
+
/javascript:/i,
|
|
89
|
+
/data:text\/html/i,
|
|
90
|
+
];
|
|
91
|
+
for (const pattern of markdownPatterns) {
|
|
92
|
+
const match = content.match(pattern);
|
|
93
|
+
if (match) {
|
|
94
|
+
issues.push({
|
|
95
|
+
rule_id: 'heuristic_markup_injection',
|
|
96
|
+
rule_name: 'Markup Injection Attempt',
|
|
97
|
+
type: 'injection',
|
|
98
|
+
severity: 'medium',
|
|
99
|
+
action: 'alert',
|
|
100
|
+
match: this.sanitizeMatch(match[0]),
|
|
101
|
+
suggestion: 'This content contains potentially dangerous markup or code injection.'
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Check for excessive special characters (potential obfuscation)
|
|
106
|
+
const specialCharRatio = this.calculateSpecialCharRatio(content);
|
|
107
|
+
if (specialCharRatio > 0.3 && content.length > 50) {
|
|
108
|
+
issues.push({
|
|
109
|
+
rule_id: 'heuristic_obfuscation',
|
|
110
|
+
rule_name: 'Potential Obfuscation',
|
|
111
|
+
type: 'injection',
|
|
112
|
+
severity: 'low',
|
|
113
|
+
action: 'log',
|
|
114
|
+
match: `Special character ratio: ${(specialCharRatio * 100).toFixed(1)}%`,
|
|
115
|
+
suggestion: 'This content has an unusually high ratio of special characters, which may indicate obfuscation.'
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return issues;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Calculate ratio of special characters
|
|
122
|
+
*/
|
|
123
|
+
calculateSpecialCharRatio(content) {
|
|
124
|
+
if (content.length === 0)
|
|
125
|
+
return 0;
|
|
126
|
+
const specialChars = content.replace(/[\w\s]/g, '').length;
|
|
127
|
+
return specialChars / content.length;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Calculate location within content
|
|
131
|
+
*/
|
|
132
|
+
getLocation(content, start, length) {
|
|
133
|
+
const end = start + length;
|
|
134
|
+
const lines = content.substring(0, start).split('\n');
|
|
135
|
+
const line = lines.length;
|
|
136
|
+
const column = lines[lines.length - 1].length + 1;
|
|
137
|
+
return { start, end, line, column };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Sanitize match for safe display
|
|
141
|
+
*/
|
|
142
|
+
sanitizeMatch(match, maxLength = 100) {
|
|
143
|
+
const sanitized = match
|
|
144
|
+
.replace(/</g, '<')
|
|
145
|
+
.replace(/>/g, '>')
|
|
146
|
+
.replace(/"/g, '"');
|
|
147
|
+
if (sanitized.length <= maxLength)
|
|
148
|
+
return sanitized;
|
|
149
|
+
return sanitized.substring(0, maxLength) + '...';
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get remediation suggestion
|
|
153
|
+
*/
|
|
154
|
+
getSuggestion(ruleId) {
|
|
155
|
+
const suggestions = {
|
|
156
|
+
prompt_injection_ignore: 'This content attempts to make the AI ignore its instructions. Do not process user inputs that contain such patterns.',
|
|
157
|
+
prompt_injection_jailbreak: 'This appears to be a jailbreak attempt. Such content should be filtered or rejected.',
|
|
158
|
+
prompt_injection_system: 'This content attempts to extract system prompts. Do not reveal system instructions.',
|
|
159
|
+
prompt_injection_roleplay: 'This content attempts to manipulate behavior through roleplay. Apply content filtering.',
|
|
160
|
+
};
|
|
161
|
+
return suggestions[ruleId] || 'This content shows signs of injection attacks. Review and sanitize input.';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
export default InjectionDetector;
|
|
165
|
+
//# sourceMappingURL=injection-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injection-detector.js","sourceRoot":"","sources":["../../src/analyzers/injection-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* PII Detector - Detects personally identifiable information
|
|
4
|
+
*/
|
|
5
|
+
import { type DetectionRule, type SecurityIssue, type IAnalyzer } from '../types.js';
|
|
6
|
+
export declare class PIIDetector implements IAnalyzer {
|
|
7
|
+
name: string;
|
|
8
|
+
type: string;
|
|
9
|
+
analyze(content: string, rules: DetectionRule[]): Promise<SecurityIssue[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Additional validation for matches to reduce false positives
|
|
12
|
+
*/
|
|
13
|
+
private validateMatch;
|
|
14
|
+
/**
|
|
15
|
+
* Validate SSN format (basic validation, not checking if real)
|
|
16
|
+
*/
|
|
17
|
+
private validateSSN;
|
|
18
|
+
/**
|
|
19
|
+
* Validate credit card using Luhn algorithm
|
|
20
|
+
*/
|
|
21
|
+
private validateCreditCard;
|
|
22
|
+
/**
|
|
23
|
+
* Validate email address format
|
|
24
|
+
*/
|
|
25
|
+
private validateEmail;
|
|
26
|
+
/**
|
|
27
|
+
* Validate IP address (exclude obvious non-IPs)
|
|
28
|
+
*/
|
|
29
|
+
private validateIPAddress;
|
|
30
|
+
/**
|
|
31
|
+
* Calculate location within content
|
|
32
|
+
*/
|
|
33
|
+
private getLocation;
|
|
34
|
+
/**
|
|
35
|
+
* Redact PII for safe display
|
|
36
|
+
*/
|
|
37
|
+
private redactPII;
|
|
38
|
+
/**
|
|
39
|
+
* Get remediation suggestion
|
|
40
|
+
*/
|
|
41
|
+
private getSuggestion;
|
|
42
|
+
}
|
|
43
|
+
export default PIIDetector;
|
|
44
|
+
//# sourceMappingURL=pii-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-detector.d.ts","sourceRoot":"","sources":["../../src/analyzers/pii-detector.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAErB,qBAAa,WAAY,YAAW,SAAS;IAC3C,IAAI,SAAiB;IACrB,IAAI,SAAS;IAEP,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAwChF;;OAEG;IACH,OAAO,CAAC,aAAa;IAerB;;OAEG;IACH,OAAO,CAAC,WAAW;IAmBnB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwB1B;;OAEG;IACH,OAAO,CAAC,aAAa;IAgBrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,SAAS;IAmBjB;;OAEG;IACH,OAAO,CAAC,aAAa;CAWtB;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* PII Detector - Detects personally identifiable information
|
|
4
|
+
*/
|
|
5
|
+
export class PIIDetector {
|
|
6
|
+
name = 'PIIDetector';
|
|
7
|
+
type = 'pii';
|
|
8
|
+
async analyze(content, rules) {
|
|
9
|
+
const issues = [];
|
|
10
|
+
const piiRules = rules.filter(r => r.type === 'pii' && r.enabled);
|
|
11
|
+
for (const rule of piiRules) {
|
|
12
|
+
if (!rule.pattern)
|
|
13
|
+
continue;
|
|
14
|
+
try {
|
|
15
|
+
const regex = new RegExp(rule.pattern, 'g');
|
|
16
|
+
let match;
|
|
17
|
+
while ((match = regex.exec(content)) !== null) {
|
|
18
|
+
const matchText = match[0];
|
|
19
|
+
// Additional validation for specific types
|
|
20
|
+
if (!this.validateMatch(rule.id, matchText)) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const location = this.getLocation(content, match.index, matchText.length);
|
|
24
|
+
issues.push({
|
|
25
|
+
rule_id: rule.id,
|
|
26
|
+
rule_name: rule.name,
|
|
27
|
+
type: rule.type,
|
|
28
|
+
severity: rule.severity,
|
|
29
|
+
action: rule.action,
|
|
30
|
+
match: this.redactPII(rule.id, matchText),
|
|
31
|
+
location,
|
|
32
|
+
suggestion: this.getSuggestion(rule.id)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error(`Invalid regex pattern in rule ${rule.id}:`, error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return issues;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Additional validation for matches to reduce false positives
|
|
44
|
+
*/
|
|
45
|
+
validateMatch(ruleId, match) {
|
|
46
|
+
switch (ruleId) {
|
|
47
|
+
case 'ssn_us':
|
|
48
|
+
return this.validateSSN(match);
|
|
49
|
+
case 'credit_card':
|
|
50
|
+
return this.validateCreditCard(match);
|
|
51
|
+
case 'email_address':
|
|
52
|
+
return this.validateEmail(match);
|
|
53
|
+
case 'ip_address':
|
|
54
|
+
return this.validateIPAddress(match);
|
|
55
|
+
default:
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validate SSN format (basic validation, not checking if real)
|
|
61
|
+
*/
|
|
62
|
+
validateSSN(ssn) {
|
|
63
|
+
const digits = ssn.replace(/\D/g, '');
|
|
64
|
+
if (digits.length !== 9)
|
|
65
|
+
return false;
|
|
66
|
+
// SSNs cannot start with 000, 666, or 900-999
|
|
67
|
+
const area = parseInt(digits.substring(0, 3));
|
|
68
|
+
if (area === 0 || area === 666 || area >= 900)
|
|
69
|
+
return false;
|
|
70
|
+
// Group number cannot be 00
|
|
71
|
+
const group = parseInt(digits.substring(3, 5));
|
|
72
|
+
if (group === 0)
|
|
73
|
+
return false;
|
|
74
|
+
// Serial number cannot be 0000
|
|
75
|
+
const serial = parseInt(digits.substring(5));
|
|
76
|
+
if (serial === 0)
|
|
77
|
+
return false;
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Validate credit card using Luhn algorithm
|
|
82
|
+
*/
|
|
83
|
+
validateCreditCard(cc) {
|
|
84
|
+
const digits = cc.replace(/\D/g, '');
|
|
85
|
+
if (digits.length < 13 || digits.length > 19)
|
|
86
|
+
return false;
|
|
87
|
+
let sum = 0;
|
|
88
|
+
let isEven = false;
|
|
89
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
90
|
+
let digit = parseInt(digits[i]);
|
|
91
|
+
if (isEven) {
|
|
92
|
+
digit *= 2;
|
|
93
|
+
if (digit > 9) {
|
|
94
|
+
digit -= 9;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
sum += digit;
|
|
98
|
+
isEven = !isEven;
|
|
99
|
+
}
|
|
100
|
+
return sum % 10 === 0;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Validate email address format
|
|
104
|
+
*/
|
|
105
|
+
validateEmail(email) {
|
|
106
|
+
// Check for common false positives
|
|
107
|
+
const falsePaths = ['.js', '.ts', '.py', '.java', '.cpp', '.go', '.rs'];
|
|
108
|
+
if (falsePaths.some(ext => email.endsWith(ext)))
|
|
109
|
+
return false;
|
|
110
|
+
// Check for reasonable length
|
|
111
|
+
if (email.length > 254)
|
|
112
|
+
return false;
|
|
113
|
+
// Check for valid TLD (at least 2 chars)
|
|
114
|
+
const parts = email.split('.');
|
|
115
|
+
const tld = parts[parts.length - 1];
|
|
116
|
+
if (tld.length < 2)
|
|
117
|
+
return false;
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Validate IP address (exclude obvious non-IPs)
|
|
122
|
+
*/
|
|
123
|
+
validateIPAddress(ip) {
|
|
124
|
+
// Exclude version numbers (e.g., 1.2.3.4 in software versions)
|
|
125
|
+
const parts = ip.split('.');
|
|
126
|
+
// All parts should be valid octets
|
|
127
|
+
for (const part of parts) {
|
|
128
|
+
const num = parseInt(part);
|
|
129
|
+
if (num < 0 || num > 255)
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
// Exclude common version patterns
|
|
133
|
+
if (parts[0] === '0' || parts[0] === '1') {
|
|
134
|
+
if (parseInt(parts[1]) <= 20 && parseInt(parts[2]) <= 20) {
|
|
135
|
+
return false; // Likely a version number
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Exclude localhost and broadcast
|
|
139
|
+
if (ip === '127.0.0.1' || ip === '0.0.0.0' || ip === '255.255.255.255') {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Calculate location within content
|
|
146
|
+
*/
|
|
147
|
+
getLocation(content, start, length) {
|
|
148
|
+
const end = start + length;
|
|
149
|
+
const lines = content.substring(0, start).split('\n');
|
|
150
|
+
const line = lines.length;
|
|
151
|
+
const column = lines[lines.length - 1].length + 1;
|
|
152
|
+
return { start, end, line, column };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Redact PII for safe display
|
|
156
|
+
*/
|
|
157
|
+
redactPII(ruleId, value) {
|
|
158
|
+
switch (ruleId) {
|
|
159
|
+
case 'ssn_us':
|
|
160
|
+
return `***-**-${value.slice(-4)}`;
|
|
161
|
+
case 'credit_card':
|
|
162
|
+
return `****-****-****-${value.slice(-4)}`;
|
|
163
|
+
case 'email_address':
|
|
164
|
+
const [local, domain] = value.split('@');
|
|
165
|
+
return `${local.charAt(0)}***@${domain}`;
|
|
166
|
+
case 'phone_number_us':
|
|
167
|
+
return `***-***-${value.slice(-4)}`;
|
|
168
|
+
case 'ip_address':
|
|
169
|
+
const parts = value.split('.');
|
|
170
|
+
return `${parts[0]}.***.***.*${parts[3].slice(-1)}`;
|
|
171
|
+
default:
|
|
172
|
+
return value.substring(0, 3) + '***' + value.slice(-2);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get remediation suggestion
|
|
177
|
+
*/
|
|
178
|
+
getSuggestion(ruleId) {
|
|
179
|
+
const suggestions = {
|
|
180
|
+
ssn_us: 'Social Security Numbers should never be stored in plain text. Use encryption or tokenization.',
|
|
181
|
+
credit_card: 'Credit card numbers must be handled according to PCI DSS standards. Use tokenization.',
|
|
182
|
+
email_address: 'Consider whether email addresses need to be logged. Hash or encrypt if stored.',
|
|
183
|
+
phone_number_us: 'Phone numbers are PII. Consider whether they need to be included.',
|
|
184
|
+
ip_address: 'IP addresses can be PII under GDPR. Consider hashing or anonymizing.'
|
|
185
|
+
};
|
|
186
|
+
return suggestions[ruleId] || 'Review whether this PII needs to be included and handle according to privacy policies.';
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export default PIIDetector;
|
|
190
|
+
//# sourceMappingURL=pii-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-detector.js","sourceRoot":"","sources":["../../src/analyzers/pii-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* Secret Scanner - Detects secrets, API keys, and credentials
|
|
4
|
+
*/
|
|
5
|
+
import { type DetectionRule, type SecurityIssue, type IAnalyzer } from '../types.js';
|
|
6
|
+
export declare class SecretScanner implements IAnalyzer {
|
|
7
|
+
name: string;
|
|
8
|
+
type: string;
|
|
9
|
+
analyze(content: string, rules: DetectionRule[]): Promise<SecurityIssue[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Calculate the location of a match within the content
|
|
12
|
+
*/
|
|
13
|
+
private getLocation;
|
|
14
|
+
/**
|
|
15
|
+
* Redact the middle portion of a secret for safe display
|
|
16
|
+
*/
|
|
17
|
+
private redactSecret;
|
|
18
|
+
/**
|
|
19
|
+
* Get remediation suggestion for a specific rule
|
|
20
|
+
*/
|
|
21
|
+
private getSuggestion;
|
|
22
|
+
/**
|
|
23
|
+
* Calculate Shannon entropy of a string (higher = more random = more likely a secret)
|
|
24
|
+
*/
|
|
25
|
+
static calculateEntropy(str: string): number;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a string is likely a high-entropy secret
|
|
28
|
+
*/
|
|
29
|
+
static isHighEntropy(str: string, threshold?: number): boolean;
|
|
30
|
+
}
|
|
31
|
+
export default SecretScanner;
|
|
32
|
+
//# sourceMappingURL=secret-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-scanner.d.ts","sourceRoot":"","sources":["../../src/analyzers/secret-scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAErB,qBAAa,aAAc,YAAW,SAAS;IAC7C,IAAI,SAAmB;IACvB,IAAI,SAAY;IAEV,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAmChF;;OAEG;IACH,OAAO,CAAC,WAAW;IAWnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAsBrB;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAkB5C;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,OAAO;CAU5D;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* Secret Scanner - Detects secrets, API keys, and credentials
|
|
4
|
+
*/
|
|
5
|
+
export class SecretScanner {
|
|
6
|
+
name = 'SecretScanner';
|
|
7
|
+
type = 'secret';
|
|
8
|
+
async analyze(content, rules) {
|
|
9
|
+
const issues = [];
|
|
10
|
+
const secretRules = rules.filter(r => r.type === 'secret' && r.enabled);
|
|
11
|
+
for (const rule of secretRules) {
|
|
12
|
+
if (!rule.pattern)
|
|
13
|
+
continue;
|
|
14
|
+
try {
|
|
15
|
+
const regex = new RegExp(rule.pattern, 'g');
|
|
16
|
+
let match;
|
|
17
|
+
while ((match = regex.exec(content)) !== null) {
|
|
18
|
+
const matchText = match[0];
|
|
19
|
+
const location = this.getLocation(content, match.index, matchText.length);
|
|
20
|
+
issues.push({
|
|
21
|
+
rule_id: rule.id,
|
|
22
|
+
rule_name: rule.name,
|
|
23
|
+
type: rule.type,
|
|
24
|
+
severity: rule.severity,
|
|
25
|
+
action: rule.action,
|
|
26
|
+
match: this.redactSecret(matchText),
|
|
27
|
+
location,
|
|
28
|
+
suggestion: this.getSuggestion(rule.id)
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
// Invalid regex pattern - skip this rule
|
|
34
|
+
console.error(`Invalid regex pattern in rule ${rule.id}:`, error);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return issues;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Calculate the location of a match within the content
|
|
41
|
+
*/
|
|
42
|
+
getLocation(content, start, length) {
|
|
43
|
+
const end = start + length;
|
|
44
|
+
// Calculate line and column
|
|
45
|
+
const lines = content.substring(0, start).split('\n');
|
|
46
|
+
const line = lines.length;
|
|
47
|
+
const column = lines[lines.length - 1].length + 1;
|
|
48
|
+
return { start, end, line, column };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Redact the middle portion of a secret for safe display
|
|
52
|
+
*/
|
|
53
|
+
redactSecret(secret) {
|
|
54
|
+
if (secret.length <= 8) {
|
|
55
|
+
return '****';
|
|
56
|
+
}
|
|
57
|
+
const visibleStart = Math.min(4, Math.floor(secret.length * 0.2));
|
|
58
|
+
const visibleEnd = Math.min(4, Math.floor(secret.length * 0.2));
|
|
59
|
+
const redactedLength = secret.length - visibleStart - visibleEnd;
|
|
60
|
+
return `${secret.substring(0, visibleStart)}${'*'.repeat(Math.min(redactedLength, 20))}${secret.substring(secret.length - visibleEnd)}`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get remediation suggestion for a specific rule
|
|
64
|
+
*/
|
|
65
|
+
getSuggestion(ruleId) {
|
|
66
|
+
const suggestions = {
|
|
67
|
+
aws_access_key_id: 'Use AWS IAM roles or environment variables instead of hardcoding credentials.',
|
|
68
|
+
aws_secret_access_key: 'Never commit AWS secret keys. Use AWS Secrets Manager or environment variables.',
|
|
69
|
+
github_token: 'Use GitHub Actions secrets or environment variables for tokens.',
|
|
70
|
+
github_fine_grained_token: 'Store GitHub tokens in a secrets manager, not in code.',
|
|
71
|
+
openai_api_key: 'Use environment variables (OPENAI_API_KEY) instead of hardcoding.',
|
|
72
|
+
anthropic_api_key: 'Use environment variables (ANTHROPIC_API_KEY) instead of hardcoding.',
|
|
73
|
+
google_api_key: 'Restrict API key usage in Google Cloud Console and use environment variables.',
|
|
74
|
+
slack_token: 'Store Slack tokens in environment variables or a secrets manager.',
|
|
75
|
+
slack_webhook: 'Webhook URLs should be stored in environment variables.',
|
|
76
|
+
stripe_api_key: 'Use environment variables. Never expose live keys in client-side code.',
|
|
77
|
+
private_key_block: 'Private keys should never be in code. Use a key management service.',
|
|
78
|
+
jwt_token: 'JWTs should be transmitted securely and never logged or stored in code.',
|
|
79
|
+
database_url: 'Database credentials should be in environment variables or a secrets manager.',
|
|
80
|
+
generic_api_key: 'API keys should be stored in environment variables or a secrets manager.',
|
|
81
|
+
generic_password: 'Passwords should never be hardcoded. Use a secrets manager.',
|
|
82
|
+
};
|
|
83
|
+
return suggestions[ruleId] || 'Remove this secret from code and use a secrets manager or environment variables.';
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Calculate Shannon entropy of a string (higher = more random = more likely a secret)
|
|
87
|
+
*/
|
|
88
|
+
static calculateEntropy(str) {
|
|
89
|
+
const len = str.length;
|
|
90
|
+
if (len === 0)
|
|
91
|
+
return 0;
|
|
92
|
+
const frequencies = {};
|
|
93
|
+
for (const char of str) {
|
|
94
|
+
frequencies[char] = (frequencies[char] || 0) + 1;
|
|
95
|
+
}
|
|
96
|
+
let entropy = 0;
|
|
97
|
+
for (const count of Object.values(frequencies)) {
|
|
98
|
+
const p = count / len;
|
|
99
|
+
entropy -= p * Math.log2(p);
|
|
100
|
+
}
|
|
101
|
+
return entropy;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check if a string is likely a high-entropy secret
|
|
105
|
+
*/
|
|
106
|
+
static isHighEntropy(str, threshold = 4.5) {
|
|
107
|
+
// Skip strings that are too short or too long
|
|
108
|
+
if (str.length < 16 || str.length > 200)
|
|
109
|
+
return false;
|
|
110
|
+
// Skip if it looks like a common word or path
|
|
111
|
+
if (/^[a-z]+$/i.test(str))
|
|
112
|
+
return false;
|
|
113
|
+
if (str.includes('/') && !str.includes('://'))
|
|
114
|
+
return false;
|
|
115
|
+
return SecretScanner.calculateEntropy(str) > threshold;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
export default SecretScanner;
|
|
119
|
+
//# sourceMappingURL=secret-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-scanner.js","sourceRoot":"","sources":["../../src/analyzers/secret-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* Constants and default configurations
|
|
4
|
+
*/
|
|
5
|
+
import type { DetectionRule, MundConfig } from './types.js';
|
|
6
|
+
export declare const DEFAULT_CONFIG: MundConfig;
|
|
7
|
+
export declare const MAX_CONTENT_LENGTH = 1000000;
|
|
8
|
+
export declare const MAX_SNIPPET_LENGTH = 200;
|
|
9
|
+
export declare const MAX_EVENTS_PER_QUERY = 1000;
|
|
10
|
+
export declare const DEFAULT_EVENTS_LIMIT = 50;
|
|
11
|
+
export declare const SECRET_PATTERNS: DetectionRule[];
|
|
12
|
+
export declare const PII_PATTERNS: DetectionRule[];
|
|
13
|
+
export declare const CODE_PATTERNS: DetectionRule[];
|
|
14
|
+
export declare const INJECTION_PATTERNS: DetectionRule[];
|
|
15
|
+
export declare const EXFILTRATION_PATTERNS: DetectionRule[];
|
|
16
|
+
export declare const DANGEROUS_URL_PATTERNS: RegExp[];
|
|
17
|
+
export declare const DEFAULT_RULES: DetectionRule[];
|
|
18
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM5D,eAAO,MAAM,cAAc,EAAE,UAQ5B,CAAC;AAMF,eAAO,MAAM,kBAAkB,UAAY,CAAC;AAC5C,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,oBAAoB,OAAO,CAAC;AACzC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAMvC,eAAO,MAAM,eAAe,EAAE,aAAa,EAuT1C,CAAC;AAMF,eAAO,MAAM,YAAY,EAAE,aAAa,EAmDvC,CAAC;AAMF,eAAO,MAAM,aAAa,EAAE,aAAa,EAuExC,CAAC;AAMF,eAAO,MAAM,kBAAkB,EAAE,aAAa,EAyC7C,CAAC;AAMF,eAAO,MAAM,qBAAqB,EAAE,aAAa,EA+BhD,CAAC;AAMF,eAAO,MAAM,sBAAsB,UAoBlC,CAAC;AAMF,eAAO,MAAM,aAAa,EAAE,aAAa,EAMxC,CAAC"}
|