vibe-guard 1.0.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/LICENSE +21 -0
- package/README.md +200 -0
- package/dist/bin/vibe-guard.d.ts +3 -0
- package/dist/bin/vibe-guard.d.ts.map +1 -0
- package/dist/bin/vibe-guard.js +119 -0
- package/dist/bin/vibe-guard.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter.d.ts +13 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +116 -0
- package/dist/reporter.js.map +1 -0
- package/dist/rules/directory-traversal.d.ts +14 -0
- package/dist/rules/directory-traversal.d.ts.map +1 -0
- package/dist/rules/directory-traversal.js +142 -0
- package/dist/rules/directory-traversal.js.map +1 -0
- package/dist/rules/exposed-secrets.d.ts +13 -0
- package/dist/rules/exposed-secrets.d.ts.map +1 -0
- package/dist/rules/exposed-secrets.js +137 -0
- package/dist/rules/exposed-secrets.js.map +1 -0
- package/dist/rules/hardcoded-sensitive-data.d.ts +13 -0
- package/dist/rules/hardcoded-sensitive-data.d.ts.map +1 -0
- package/dist/rules/hardcoded-sensitive-data.js +104 -0
- package/dist/rules/hardcoded-sensitive-data.js.map +1 -0
- package/dist/rules/index.d.ts +15 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +54 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/insecure-dependencies.d.ts +16 -0
- package/dist/rules/insecure-dependencies.d.ts.map +1 -0
- package/dist/rules/insecure-dependencies.js +152 -0
- package/dist/rules/insecure-dependencies.js.map +1 -0
- package/dist/rules/insecure-http.d.ts +13 -0
- package/dist/rules/insecure-http.d.ts.map +1 -0
- package/dist/rules/insecure-http.js +91 -0
- package/dist/rules/insecure-http.js.map +1 -0
- package/dist/rules/missing-authentication.d.ts +14 -0
- package/dist/rules/missing-authentication.d.ts.map +1 -0
- package/dist/rules/missing-authentication.js +98 -0
- package/dist/rules/missing-authentication.js.map +1 -0
- package/dist/rules/missing-security-headers.d.ts +16 -0
- package/dist/rules/missing-security-headers.d.ts.map +1 -0
- package/dist/rules/missing-security-headers.js +158 -0
- package/dist/rules/missing-security-headers.js.map +1 -0
- package/dist/rules/open-cors.d.ts +11 -0
- package/dist/rules/open-cors.d.ts.map +1 -0
- package/dist/rules/open-cors.js +61 -0
- package/dist/rules/open-cors.js.map +1 -0
- package/dist/rules/sql-injection.d.ts +12 -0
- package/dist/rules/sql-injection.d.ts.map +1 -0
- package/dist/rules/sql-injection.js +95 -0
- package/dist/rules/sql-injection.js.map +1 -0
- package/dist/rules/unvalidated-input.d.ts +13 -0
- package/dist/rules/unvalidated-input.d.ts.map +1 -0
- package/dist/rules/unvalidated-input.js +128 -0
- package/dist/rules/unvalidated-input.js.map +1 -0
- package/dist/scanner.d.ts +15 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +240 -0
- package/dist/scanner.js.map +1 -0
- package/dist/types/index.d.ts +66 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +38 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InsecureDependenciesRule = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
class InsecureDependenciesRule extends types_1.BaseRule {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.name = 'insecure-dependencies';
|
|
9
|
+
this.description = 'Detects potentially insecure dependencies and packages';
|
|
10
|
+
this.severity = 'medium';
|
|
11
|
+
this.vulnerablePackages = [
|
|
12
|
+
// Known vulnerable packages
|
|
13
|
+
{ name: 'lodash', versions: ['<4.17.21'], reason: 'Prototype pollution vulnerabilities' },
|
|
14
|
+
{ name: 'moment', versions: ['*'], reason: 'Deprecated package, use date-fns or dayjs instead' },
|
|
15
|
+
{ name: 'request', versions: ['*'], reason: 'Deprecated package with security issues' },
|
|
16
|
+
{ name: 'node-uuid', versions: ['*'], reason: 'Deprecated, use uuid package instead' },
|
|
17
|
+
{ name: 'growl', versions: ['<1.10.0'], reason: 'Command injection vulnerability' },
|
|
18
|
+
{ name: 'handlebars', versions: ['<4.7.7'], reason: 'Template injection vulnerabilities' },
|
|
19
|
+
{ name: 'serialize-javascript', versions: ['<3.1.0'], reason: 'XSS vulnerability' },
|
|
20
|
+
{ name: 'minimist', versions: ['<1.2.6'], reason: 'Prototype pollution vulnerability' },
|
|
21
|
+
{ name: 'yargs-parser', versions: ['<13.1.2'], reason: 'Prototype pollution vulnerability' },
|
|
22
|
+
{ name: 'ini', versions: ['<1.3.6'], reason: 'Prototype pollution vulnerability' },
|
|
23
|
+
// Python packages
|
|
24
|
+
{ name: 'django', versions: ['<3.2.13'], reason: 'Multiple security vulnerabilities' },
|
|
25
|
+
{ name: 'flask', versions: ['<2.0.0'], reason: 'Security improvements in newer versions' },
|
|
26
|
+
{ name: 'requests', versions: ['<2.20.0'], reason: 'SSL verification issues' },
|
|
27
|
+
{ name: 'pyyaml', versions: ['<5.4'], reason: 'Arbitrary code execution vulnerability' },
|
|
28
|
+
{ name: 'pillow', versions: ['<8.3.2'], reason: 'Multiple image processing vulnerabilities' },
|
|
29
|
+
// PHP packages
|
|
30
|
+
{ name: 'symfony/symfony', versions: ['<4.4.35'], reason: 'Multiple security vulnerabilities' },
|
|
31
|
+
{ name: 'laravel/framework', versions: ['<8.75.0'], reason: 'Security vulnerabilities' },
|
|
32
|
+
{ name: 'monolog/monolog', versions: ['<2.3.5'], reason: 'Remote code execution vulnerability' }
|
|
33
|
+
];
|
|
34
|
+
this.suspiciousPatterns = [
|
|
35
|
+
// Suspicious package names
|
|
36
|
+
{ pattern: /(?:^|\s)(?:eval|exec|shell|cmd|system|proc|spawn)(?:-|_)?(?:js|py|php|rb)?\s*[:=]/gi, type: 'Suspicious package name' },
|
|
37
|
+
{ pattern: /(?:^|\s)(?:backdoor|malware|virus|trojan|keylogger)\s*[:=]/gi, type: 'Malicious package name' },
|
|
38
|
+
// Typosquatting patterns (common misspellings)
|
|
39
|
+
{ pattern: /(?:^|\s)(?:lodahs|momnet|expres|reactt|angualr|vuejs)\s*[:=]/gi, type: 'Potential typosquatting' },
|
|
40
|
+
// Suspicious version patterns
|
|
41
|
+
{ pattern: /["'](?:\*|latest|>.*|>=.*\|\|.*|.*\.\*\.\*)["']/g, type: 'Overly permissive version range' },
|
|
42
|
+
// Development dependencies in production
|
|
43
|
+
{ pattern: /"devDependencies"\s*:\s*\{[^}]*"(?:nodemon|webpack-dev-server|jest|mocha|chai|sinon)"/gi, type: 'Development dependency' }
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
check(fileContent) {
|
|
47
|
+
const issues = [];
|
|
48
|
+
// Only check dependency files
|
|
49
|
+
if (!this.isDependencyFile(fileContent.path)) {
|
|
50
|
+
return issues;
|
|
51
|
+
}
|
|
52
|
+
// Check for vulnerable packages
|
|
53
|
+
this.checkVulnerablePackages(fileContent, issues);
|
|
54
|
+
// Check for suspicious patterns
|
|
55
|
+
this.checkSuspiciousPatterns(fileContent, issues);
|
|
56
|
+
return issues;
|
|
57
|
+
}
|
|
58
|
+
isDependencyFile(filePath) {
|
|
59
|
+
const dependencyFiles = [
|
|
60
|
+
/package\.json$/i,
|
|
61
|
+
/requirements\.txt$/i,
|
|
62
|
+
/Pipfile$/i,
|
|
63
|
+
/composer\.json$/i,
|
|
64
|
+
/Gemfile$/i,
|
|
65
|
+
/pom\.xml$/i,
|
|
66
|
+
/build\.gradle$/i,
|
|
67
|
+
/yarn\.lock$/i,
|
|
68
|
+
/package-lock\.json$/i
|
|
69
|
+
];
|
|
70
|
+
return dependencyFiles.some(pattern => pattern.test(filePath));
|
|
71
|
+
}
|
|
72
|
+
checkVulnerablePackages(fileContent, issues) {
|
|
73
|
+
for (const pkg of this.vulnerablePackages) {
|
|
74
|
+
const pattern = new RegExp(`["']${pkg.name}["']\\s*:\\s*["']([^"']+)["']`, 'gi');
|
|
75
|
+
const matches = this.findMatches(fileContent.content, pattern);
|
|
76
|
+
for (const { match, line, column, lineContent } of matches) {
|
|
77
|
+
const version = match[1];
|
|
78
|
+
if (version && this.isVulnerableVersion(version, pkg.versions)) {
|
|
79
|
+
issues.push(this.createIssue(fileContent.path, line, column, lineContent, `Vulnerable dependency: ${pkg.name}@${version}`, `${pkg.reason}. Update to a secure version or find an alternative package.`));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
checkSuspiciousPatterns(fileContent, issues) {
|
|
85
|
+
for (const { pattern, type } of this.suspiciousPatterns) {
|
|
86
|
+
const matches = this.findMatches(fileContent.content, pattern);
|
|
87
|
+
for (const { line, column, lineContent } of matches) {
|
|
88
|
+
// Skip development dependencies check if it's actually in devDependencies section
|
|
89
|
+
if (type === 'Development dependency' && this.isInDevDependencies(fileContent.content, line)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
issues.push(this.createIssue(fileContent.path, line, column, lineContent, `Suspicious dependency pattern: ${type}`, `Review this dependency carefully. Ensure it's from a trusted source and serves a legitimate purpose.`));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
isVulnerableVersion(version, vulnerableVersions) {
|
|
97
|
+
// Simple version checking - in a real implementation, you'd use semver
|
|
98
|
+
for (const vulnVersion of vulnerableVersions) {
|
|
99
|
+
if (vulnVersion === '*') {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
if (vulnVersion.startsWith('<')) {
|
|
103
|
+
// This is a simplified check - real implementation would use proper semver comparison
|
|
104
|
+
const targetVersion = vulnVersion.substring(1);
|
|
105
|
+
if (this.compareVersions(version, targetVersion) < 0) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (version === vulnVersion) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
compareVersions(version1, version2) {
|
|
116
|
+
// Simplified version comparison - real implementation would handle all semver cases
|
|
117
|
+
const v1Parts = version1.replace(/[^\d.]/g, '').split('.').map(Number);
|
|
118
|
+
const v2Parts = version2.replace(/[^\d.]/g, '').split('.').map(Number);
|
|
119
|
+
for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
|
|
120
|
+
const v1Part = v1Parts[i] || 0;
|
|
121
|
+
const v2Part = v2Parts[i] || 0;
|
|
122
|
+
if (v1Part < v2Part)
|
|
123
|
+
return -1;
|
|
124
|
+
if (v1Part > v2Part)
|
|
125
|
+
return 1;
|
|
126
|
+
}
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
isInDevDependencies(content, lineNumber) {
|
|
130
|
+
const lines = content.split('\n');
|
|
131
|
+
// Look backwards from the current line to find the section
|
|
132
|
+
for (let i = lineNumber - 1; i >= 0; i--) {
|
|
133
|
+
const line = lines[i];
|
|
134
|
+
if (!line)
|
|
135
|
+
continue;
|
|
136
|
+
const trimmedLine = line.trim();
|
|
137
|
+
if (trimmedLine.includes('"devDependencies"')) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
if (trimmedLine.includes('"dependencies"') && !trimmedLine.includes('"devDependencies"')) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
// If we hit another top-level section, stop looking
|
|
144
|
+
if (trimmedLine.match(/^"[^"]+"\s*:\s*\{/) && !trimmedLine.includes('Dependencies')) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.InsecureDependenciesRule = InsecureDependenciesRule;
|
|
152
|
+
//# sourceMappingURL=insecure-dependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insecure-dependencies.js","sourceRoot":"","sources":["../../src/rules/insecure-dependencies.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseRule, FileContent, SecurityIssue } from '../types';
|
|
2
|
+
export declare class InsecureHttpRule extends BaseRule {
|
|
3
|
+
readonly name = "insecure-http";
|
|
4
|
+
readonly description = "Detects insecure HTTP usage instead of HTTPS";
|
|
5
|
+
readonly severity: "medium";
|
|
6
|
+
private readonly httpPatterns;
|
|
7
|
+
private readonly safePatterns;
|
|
8
|
+
check(fileContent: FileContent): SecurityIssue[];
|
|
9
|
+
private isDevelopmentContext;
|
|
10
|
+
private isTestFile;
|
|
11
|
+
private extractUrl;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=insecure-http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insecure-http.d.ts","sourceRoot":"","sources":["../../src/rules/insecure-http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEhE,qBAAa,gBAAiB,SAAQ,QAAQ;IAC5C,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,WAAW,kDAAkD;IACtE,QAAQ,CAAC,QAAQ,EAAG,QAAQ,CAAU;IAEtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CA4B3B;IAEF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAY3B;IAEF,KAAK,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa,EAAE;IAiChD,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,UAAU;IAiBlB,OAAO,CAAC,UAAU;CAInB"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InsecureHttpRule = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
class InsecureHttpRule extends types_1.BaseRule {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.name = 'insecure-http';
|
|
9
|
+
this.description = 'Detects insecure HTTP usage instead of HTTPS';
|
|
10
|
+
this.severity = 'medium';
|
|
11
|
+
this.httpPatterns = [
|
|
12
|
+
// Direct HTTP URLs
|
|
13
|
+
{ pattern: /['"`]http:\/\/(?!localhost|127\.0\.0\.1|0\.0\.0\.0)[^'"`\s]+['"`]/gi, type: 'HTTP URL' },
|
|
14
|
+
// API endpoints
|
|
15
|
+
{ pattern: /(?:api_url|endpoint|base_url)\s*[:=]\s*['"`]http:\/\/[^'"`\s]+['"`]/gi, type: 'HTTP API Endpoint' },
|
|
16
|
+
{ pattern: /fetch\s*\(\s*['"`]http:\/\/[^'"`\s]+['"`]/gi, type: 'HTTP Fetch Request' },
|
|
17
|
+
{ pattern: /axios\.(?:get|post|put|delete)\s*\(\s*['"`]http:\/\/[^'"`\s]+['"`]/gi, type: 'HTTP Axios Request' },
|
|
18
|
+
// Configuration
|
|
19
|
+
{ pattern: /(?:protocol|scheme)\s*[:=]\s*['"`]http['"`]/gi, type: 'HTTP Protocol Configuration' },
|
|
20
|
+
{ pattern: /secure\s*[:=]\s*false/gi, type: 'Insecure Configuration' },
|
|
21
|
+
// Express/Node.js specific
|
|
22
|
+
{ pattern: /app\.listen\s*\(\s*\d+\s*,\s*['"`]0\.0\.0\.0['"`]/gi, type: 'HTTP Server Binding' },
|
|
23
|
+
{ pattern: /createServer\s*\(\s*(?!.*https)/gi, type: 'HTTP Server Creation' },
|
|
24
|
+
// Cookie security
|
|
25
|
+
{ pattern: /httpOnly\s*:\s*false/gi, type: 'Insecure Cookie Configuration' },
|
|
26
|
+
{ pattern: /secure\s*:\s*false/gi, type: 'Insecure Cookie Security' },
|
|
27
|
+
// Mixed content
|
|
28
|
+
{ pattern: /src\s*=\s*['"`]http:\/\/[^'"`\s]+['"`]/gi, type: 'Mixed Content Resource' },
|
|
29
|
+
{ pattern: /href\s*=\s*['"`]http:\/\/[^'"`\s]+['"`]/gi, type: 'Mixed Content Link' },
|
|
30
|
+
// Framework specific
|
|
31
|
+
{ pattern: /@RequestMapping.*http:/gi, type: 'HTTP Spring Mapping' },
|
|
32
|
+
{ pattern: /ALLOWED_HOSTS\s*=\s*\[\s*['"`]\*['"`]/gi, type: 'Permissive Host Configuration' }
|
|
33
|
+
];
|
|
34
|
+
this.safePatterns = [
|
|
35
|
+
/localhost/i,
|
|
36
|
+
/127\.0\.0\.1/,
|
|
37
|
+
/0\.0\.0\.0/,
|
|
38
|
+
/\.local/i,
|
|
39
|
+
/development/i,
|
|
40
|
+
/dev/i,
|
|
41
|
+
/staging/i,
|
|
42
|
+
/test/i,
|
|
43
|
+
/mock/i,
|
|
44
|
+
/example/i,
|
|
45
|
+
/placeholder/i
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
check(fileContent) {
|
|
49
|
+
const issues = [];
|
|
50
|
+
for (const { pattern, type } of this.httpPatterns) {
|
|
51
|
+
const matches = this.findMatches(fileContent.content, pattern);
|
|
52
|
+
for (const { match, line, column, lineContent } of matches) {
|
|
53
|
+
const matchedText = match[0];
|
|
54
|
+
// Skip if it's in a development/test context
|
|
55
|
+
if (this.isDevelopmentContext(matchedText) || this.isDevelopmentContext(lineContent)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// Skip if the file appears to be a test or development file
|
|
59
|
+
if (this.isTestFile(fileContent.path)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
issues.push(this.createIssue(fileContent.path, line, column, lineContent, `Insecure ${type} detected: ${this.extractUrl(matchedText)}`, `Use HTTPS instead of HTTP for secure communication. Replace 'http://' with 'https://' and ensure SSL/TLS certificates are properly configured.`));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return issues;
|
|
66
|
+
}
|
|
67
|
+
isDevelopmentContext(text) {
|
|
68
|
+
return this.safePatterns.some(pattern => pattern.test(text));
|
|
69
|
+
}
|
|
70
|
+
isTestFile(filePath) {
|
|
71
|
+
const testPatterns = [
|
|
72
|
+
/test/i,
|
|
73
|
+
/spec/i,
|
|
74
|
+
/\.test\./i,
|
|
75
|
+
/\.spec\./i,
|
|
76
|
+
/__tests__/i,
|
|
77
|
+
/tests\//i,
|
|
78
|
+
/spec\//i,
|
|
79
|
+
/dev/i,
|
|
80
|
+
/development/i,
|
|
81
|
+
/local/i
|
|
82
|
+
];
|
|
83
|
+
return testPatterns.some(pattern => pattern.test(filePath));
|
|
84
|
+
}
|
|
85
|
+
extractUrl(text) {
|
|
86
|
+
const urlMatch = text.match(/http:\/\/[^'"`\s]+/);
|
|
87
|
+
return urlMatch ? urlMatch[0] : text;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.InsecureHttpRule = InsecureHttpRule;
|
|
91
|
+
//# sourceMappingURL=insecure-http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"insecure-http.js","sourceRoot":"","sources":["../../src/rules/insecure-http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseRule, FileContent, SecurityIssue } from '../types';
|
|
2
|
+
export declare class MissingAuthenticationRule extends BaseRule {
|
|
3
|
+
readonly name = "missing-authentication";
|
|
4
|
+
readonly description = "Detects potentially unprotected routes and endpoints";
|
|
5
|
+
readonly severity: "high";
|
|
6
|
+
private readonly routePatterns;
|
|
7
|
+
private readonly protectedPatterns;
|
|
8
|
+
private readonly publicEndpoints;
|
|
9
|
+
check(fileContent: FileContent): SecurityIssue[];
|
|
10
|
+
private extractRoute;
|
|
11
|
+
private isPublicEndpoint;
|
|
12
|
+
private hasAuthenticationContext;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=missing-authentication.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-authentication.d.ts","sourceRoot":"","sources":["../../src/rules/missing-authentication.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEhE,qBAAa,yBAA0B,SAAQ,QAAQ;IACrD,QAAQ,CAAC,IAAI,4BAA4B;IACzC,QAAQ,CAAC,WAAW,0DAA0D;IAC9E,QAAQ,CAAC,QAAQ,EAAG,MAAM,CAAU;IAEpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAgB5B;IAEF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAahC;IAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAgB9B;IAEF,KAAK,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa,EAAE;IAiChD,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,wBAAwB;CAWjC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MissingAuthenticationRule = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
class MissingAuthenticationRule extends types_1.BaseRule {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.name = 'missing-authentication';
|
|
9
|
+
this.description = 'Detects potentially unprotected routes and endpoints';
|
|
10
|
+
this.severity = 'high';
|
|
11
|
+
this.routePatterns = [
|
|
12
|
+
// Express.js
|
|
13
|
+
{ pattern: /app\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]\s*,\s*(?!.*auth|.*login|.*verify|.*middleware)/gi, framework: 'Express' },
|
|
14
|
+
{ pattern: /router\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]\s*,\s*(?!.*auth|.*login|.*verify|.*middleware)/gi, framework: 'Express' },
|
|
15
|
+
// Next.js API routes
|
|
16
|
+
{ pattern: /export\s+(?:default\s+)?(?:async\s+)?function\s+handler\s*\([^)]*\)\s*\{(?![\s\S]*auth|[\s\S]*login|[\s\S]*verify)/gi, framework: 'Next.js' },
|
|
17
|
+
// Flask
|
|
18
|
+
{ pattern: /@app\.route\s*\(\s*['"`]([^'"`]+)['"`](?:[^)]*)\)\s*\n\s*def\s+\w+\s*\([^)]*\)\s*:(?![\s\S]*auth|[\s\S]*login|[\s\S]*verify)/gi, framework: 'Flask' },
|
|
19
|
+
// FastAPI
|
|
20
|
+
{ pattern: /@app\.(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]\s*\)\s*\n\s*(?:async\s+)?def\s+\w+\s*\([^)]*\)\s*:(?![\s\S]*auth|[\s\S]*login|[\s\S]*verify)/gi, framework: 'FastAPI' },
|
|
21
|
+
// Laravel
|
|
22
|
+
{ pattern: /Route::(get|post|put|delete|patch)\s*\(\s*['"`]([^'"`]+)['"`]\s*,\s*(?!.*auth|.*login|.*verify|.*middleware)/gi, framework: 'Laravel' }
|
|
23
|
+
];
|
|
24
|
+
this.protectedPatterns = [
|
|
25
|
+
/auth/i,
|
|
26
|
+
/login/i,
|
|
27
|
+
/verify/i,
|
|
28
|
+
/middleware/i,
|
|
29
|
+
/guard/i,
|
|
30
|
+
/protect/i,
|
|
31
|
+
/secure/i,
|
|
32
|
+
/jwt/i,
|
|
33
|
+
/token/i,
|
|
34
|
+
/session/i,
|
|
35
|
+
/permission/i,
|
|
36
|
+
/role/i
|
|
37
|
+
];
|
|
38
|
+
this.publicEndpoints = [
|
|
39
|
+
/\/public/i,
|
|
40
|
+
/\/health/i,
|
|
41
|
+
/\/ping/i,
|
|
42
|
+
/\/status/i,
|
|
43
|
+
/\/docs/i,
|
|
44
|
+
/\/swagger/i,
|
|
45
|
+
/\/api-docs/i,
|
|
46
|
+
/\/favicon/i,
|
|
47
|
+
/\/robots\.txt/i,
|
|
48
|
+
/\/sitemap/i,
|
|
49
|
+
/\/login/i,
|
|
50
|
+
/\/register/i,
|
|
51
|
+
/\/signup/i,
|
|
52
|
+
/\/forgot-password/i,
|
|
53
|
+
/\/reset-password/i
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
check(fileContent) {
|
|
57
|
+
const issues = [];
|
|
58
|
+
for (const { pattern, framework } of this.routePatterns) {
|
|
59
|
+
const matches = this.findMatches(fileContent.content, pattern);
|
|
60
|
+
for (const { match, line, column, lineContent } of matches) {
|
|
61
|
+
const route = this.extractRoute(match);
|
|
62
|
+
// Skip if it's a known public endpoint
|
|
63
|
+
if (this.isPublicEndpoint(route)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
// Skip if the surrounding code suggests authentication
|
|
67
|
+
if (this.hasAuthenticationContext(fileContent.content, line)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
issues.push(this.createIssue(fileContent.path, line, column, lineContent, `Potentially unprotected ${framework} route: ${route}`, `Add authentication middleware or verify that this endpoint should be publicly accessible. Consider using authentication guards, middleware, or decorators.`));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return issues;
|
|
74
|
+
}
|
|
75
|
+
extractRoute(match) {
|
|
76
|
+
// Try to find the route path in the match
|
|
77
|
+
for (let i = 1; i < match.length; i++) {
|
|
78
|
+
const matchGroup = match[i];
|
|
79
|
+
if (matchGroup && matchGroup.startsWith('/')) {
|
|
80
|
+
return matchGroup;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return match[0] || '';
|
|
84
|
+
}
|
|
85
|
+
isPublicEndpoint(route) {
|
|
86
|
+
return this.publicEndpoints.some(pattern => pattern.test(route));
|
|
87
|
+
}
|
|
88
|
+
hasAuthenticationContext(content, lineNumber) {
|
|
89
|
+
const lines = content.split('\n');
|
|
90
|
+
const contextRange = 10; // Check 10 lines before and after
|
|
91
|
+
const startLine = Math.max(0, lineNumber - contextRange - 1);
|
|
92
|
+
const endLine = Math.min(lines.length, lineNumber + contextRange);
|
|
93
|
+
const contextLines = lines.slice(startLine, endLine).join('\n');
|
|
94
|
+
return this.protectedPatterns.some(pattern => pattern.test(contextLines));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
exports.MissingAuthenticationRule = MissingAuthenticationRule;
|
|
98
|
+
//# sourceMappingURL=missing-authentication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-authentication.js","sourceRoot":"","sources":["../../src/rules/missing-authentication.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseRule, FileContent, SecurityIssue } from '../types';
|
|
2
|
+
export declare class MissingSecurityHeadersRule extends BaseRule {
|
|
3
|
+
readonly name = "missing-security-headers";
|
|
4
|
+
readonly description = "Detects missing HTTP security headers";
|
|
5
|
+
readonly severity: "medium";
|
|
6
|
+
private readonly securityHeaders;
|
|
7
|
+
private readonly serverPatterns;
|
|
8
|
+
check(fileContent: FileContent): SecurityIssue[];
|
|
9
|
+
private isWebApplicationFile;
|
|
10
|
+
private hasServerCode;
|
|
11
|
+
private checkMissingHeaders;
|
|
12
|
+
private hasSecurityHeader;
|
|
13
|
+
private findReportLocation;
|
|
14
|
+
private getHeaderRecommendations;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=missing-security-headers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-security-headers.d.ts","sourceRoot":"","sources":["../../src/rules/missing-security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEhE,qBAAa,0BAA2B,SAAQ,QAAQ;IACtD,QAAQ,CAAC,IAAI,8BAA8B;IAC3C,QAAQ,CAAC,WAAW,2CAA2C;IAC/D,QAAQ,CAAC,QAAQ,EAAG,QAAQ,CAAU;IAEtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAS9B;IAEF,OAAO,CAAC,QAAQ,CAAC,cAAc,CA4B7B;IAEF,KAAK,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa,EAAE;IAoBhD,OAAO,CAAC,oBAAoB;IA8B5B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,wBAAwB;CAqBjC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MissingSecurityHeadersRule = void 0;
|
|
4
|
+
const types_1 = require("../types");
|
|
5
|
+
class MissingSecurityHeadersRule extends types_1.BaseRule {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.name = 'missing-security-headers';
|
|
9
|
+
this.description = 'Detects missing HTTP security headers';
|
|
10
|
+
this.severity = 'medium';
|
|
11
|
+
this.securityHeaders = [
|
|
12
|
+
'Content-Security-Policy',
|
|
13
|
+
'X-Frame-Options',
|
|
14
|
+
'X-Content-Type-Options',
|
|
15
|
+
'X-XSS-Protection',
|
|
16
|
+
'Strict-Transport-Security',
|
|
17
|
+
'Referrer-Policy',
|
|
18
|
+
'Permissions-Policy',
|
|
19
|
+
'X-Permitted-Cross-Domain-Policies'
|
|
20
|
+
];
|
|
21
|
+
this.serverPatterns = [
|
|
22
|
+
// Express.js patterns
|
|
23
|
+
{ pattern: /app\.(?:get|post|put|delete|patch|use)\s*\(/gi, type: 'Express route handler' },
|
|
24
|
+
{ pattern: /router\.(?:get|post|put|delete|patch|use)\s*\(/gi, type: 'Express router' },
|
|
25
|
+
{ pattern: /app\.listen\s*\(/gi, type: 'Express server' },
|
|
26
|
+
// Next.js API routes
|
|
27
|
+
{ pattern: /export\s+(?:default\s+)?(?:async\s+)?function\s+handler/gi, type: 'Next.js API handler' },
|
|
28
|
+
{ pattern: /export\s+(?:const|let|var)\s+\w+\s*=\s*(?:async\s+)?\([^)]*req[^)]*res[^)]*\)/gi, type: 'Next.js API function' },
|
|
29
|
+
// Node.js HTTP server
|
|
30
|
+
{ pattern: /createServer\s*\(\s*(?:async\s+)?\([^)]*req[^)]*res[^)]*\)/gi, type: 'Node.js HTTP server' },
|
|
31
|
+
{ pattern: /http\.createServer/gi, type: 'HTTP server creation' },
|
|
32
|
+
// Framework response patterns
|
|
33
|
+
{ pattern: /res\.(?:send|json|render|redirect)/gi, type: 'Response method' },
|
|
34
|
+
{ pattern: /response\.(?:send|json|render|redirect)/gi, type: 'Response method' },
|
|
35
|
+
// Flask patterns
|
|
36
|
+
{ pattern: /@app\.route/gi, type: 'Flask route' },
|
|
37
|
+
{ pattern: /return\s+(?:render_template|jsonify|redirect)/gi, type: 'Flask response' },
|
|
38
|
+
// Django patterns
|
|
39
|
+
{ pattern: /def\s+\w+\s*\([^)]*request[^)]*\)/gi, type: 'Django view function' },
|
|
40
|
+
{ pattern: /HttpResponse\s*\(/gi, type: 'Django HTTP response' },
|
|
41
|
+
// PHP patterns
|
|
42
|
+
{ pattern: /header\s*\(\s*['"`][^'"`]*['"`]/gi, type: 'PHP header function' }
|
|
43
|
+
];
|
|
44
|
+
}
|
|
45
|
+
check(fileContent) {
|
|
46
|
+
const issues = [];
|
|
47
|
+
// Only check server/web application files
|
|
48
|
+
if (!this.isWebApplicationFile(fileContent.path)) {
|
|
49
|
+
return issues;
|
|
50
|
+
}
|
|
51
|
+
// Check if file contains server/route patterns
|
|
52
|
+
const hasServerCode = this.hasServerCode(fileContent.content);
|
|
53
|
+
if (!hasServerCode) {
|
|
54
|
+
return issues;
|
|
55
|
+
}
|
|
56
|
+
// Check for missing security headers
|
|
57
|
+
this.checkMissingHeaders(fileContent, issues);
|
|
58
|
+
return issues;
|
|
59
|
+
}
|
|
60
|
+
isWebApplicationFile(filePath) {
|
|
61
|
+
const webFiles = [
|
|
62
|
+
/\.js$/i,
|
|
63
|
+
/\.ts$/i,
|
|
64
|
+
/\.jsx$/i,
|
|
65
|
+
/\.tsx$/i,
|
|
66
|
+
/\.py$/i,
|
|
67
|
+
/\.php$/i,
|
|
68
|
+
/\.rb$/i,
|
|
69
|
+
/\.go$/i,
|
|
70
|
+
/\.java$/i,
|
|
71
|
+
/\.cs$/i
|
|
72
|
+
];
|
|
73
|
+
// Skip test files
|
|
74
|
+
const testPatterns = [
|
|
75
|
+
/test/i,
|
|
76
|
+
/spec/i,
|
|
77
|
+
/\.test\./i,
|
|
78
|
+
/\.spec\./i,
|
|
79
|
+
/__tests__/i
|
|
80
|
+
];
|
|
81
|
+
if (testPatterns.some(pattern => pattern.test(filePath))) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return webFiles.some(pattern => pattern.test(filePath));
|
|
85
|
+
}
|
|
86
|
+
hasServerCode(content) {
|
|
87
|
+
return this.serverPatterns.some(({ pattern }) => pattern.test(content));
|
|
88
|
+
}
|
|
89
|
+
checkMissingHeaders(fileContent, issues) {
|
|
90
|
+
const content = fileContent.content;
|
|
91
|
+
const missingHeaders = [];
|
|
92
|
+
for (const header of this.securityHeaders) {
|
|
93
|
+
if (!this.hasSecurityHeader(content, header)) {
|
|
94
|
+
missingHeaders.push(header);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (missingHeaders.length > 0) {
|
|
98
|
+
// Find a good location to report the issue (first route handler or server setup)
|
|
99
|
+
const location = this.findReportLocation(fileContent);
|
|
100
|
+
if (location) {
|
|
101
|
+
issues.push(this.createIssue(fileContent.path, location.line, location.column, location.lineContent, `Missing security headers: ${missingHeaders.join(', ')}`, `Add security headers to protect against common attacks. Consider using helmet.js for Express or implementing headers manually: ${this.getHeaderRecommendations(missingHeaders)}`));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
hasSecurityHeader(content, header) {
|
|
106
|
+
const headerPatterns = [
|
|
107
|
+
// Express.js patterns
|
|
108
|
+
new RegExp(`res\\.(?:set|header)\\s*\\(\\s*['"\`]${header}['"\`]`, 'gi'),
|
|
109
|
+
new RegExp(`res\\.setHeader\\s*\\(\\s*['"\`]${header}['"\`]`, 'gi'),
|
|
110
|
+
// Helmet.js patterns
|
|
111
|
+
/helmet\s*\(\s*\)/gi,
|
|
112
|
+
/helmet\./gi,
|
|
113
|
+
// Manual header setting
|
|
114
|
+
new RegExp(`['"\`]${header}['"\`]\\s*:\\s*['"\`]`, 'gi'),
|
|
115
|
+
// PHP patterns
|
|
116
|
+
new RegExp(`header\\s*\\(\\s*['"\`]${header}:`, 'gi'),
|
|
117
|
+
// Python Flask patterns
|
|
118
|
+
new RegExp(`response\\.headers\\[['"\`]${header}['"\`]\\]`, 'gi'),
|
|
119
|
+
// Django patterns
|
|
120
|
+
new RegExp(`response\\[['"\`]${header}['"\`]\\]`, 'gi')
|
|
121
|
+
];
|
|
122
|
+
return headerPatterns.some(pattern => pattern.test(content));
|
|
123
|
+
}
|
|
124
|
+
findReportLocation(fileContent) {
|
|
125
|
+
for (const { pattern } of this.serverPatterns) {
|
|
126
|
+
const matches = this.findMatches(fileContent.content, pattern);
|
|
127
|
+
if (matches.length > 0) {
|
|
128
|
+
const firstMatch = matches[0];
|
|
129
|
+
if (firstMatch) {
|
|
130
|
+
return {
|
|
131
|
+
line: firstMatch.line,
|
|
132
|
+
column: firstMatch.column,
|
|
133
|
+
lineContent: firstMatch.lineContent
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
getHeaderRecommendations(missingHeaders) {
|
|
141
|
+
const recommendations = [];
|
|
142
|
+
if (missingHeaders.includes('Content-Security-Policy')) {
|
|
143
|
+
recommendations.push("CSP: \"default-src 'self'\"");
|
|
144
|
+
}
|
|
145
|
+
if (missingHeaders.includes('X-Frame-Options')) {
|
|
146
|
+
recommendations.push("X-Frame-Options: 'DENY'");
|
|
147
|
+
}
|
|
148
|
+
if (missingHeaders.includes('X-Content-Type-Options')) {
|
|
149
|
+
recommendations.push("X-Content-Type-Options: 'nosniff'");
|
|
150
|
+
}
|
|
151
|
+
if (missingHeaders.includes('Strict-Transport-Security')) {
|
|
152
|
+
recommendations.push("HSTS: 'max-age=31536000; includeSubDomains'");
|
|
153
|
+
}
|
|
154
|
+
return recommendations.slice(0, 2).join(', ') + (recommendations.length > 2 ? '...' : '');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.MissingSecurityHeadersRule = MissingSecurityHeadersRule;
|
|
158
|
+
//# sourceMappingURL=missing-security-headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-security-headers.js","sourceRoot":"","sources":["../../src/rules/missing-security-headers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseRule, FileContent, SecurityIssue } from '../types';
|
|
2
|
+
export declare class OpenCorsRule extends BaseRule {
|
|
3
|
+
readonly name = "open-cors";
|
|
4
|
+
readonly description = "Detects overly permissive CORS configurations";
|
|
5
|
+
readonly severity: "high";
|
|
6
|
+
private readonly corsPatterns;
|
|
7
|
+
private readonly safePatterns;
|
|
8
|
+
check(fileContent: FileContent): SecurityIssue[];
|
|
9
|
+
private isDevelopmentContext;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=open-cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-cors.d.ts","sourceRoot":"","sources":["../../src/rules/open-cors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEhE,qBAAa,YAAa,SAAQ,QAAQ;IACxC,QAAQ,CAAC,IAAI,eAAe;IAC5B,QAAQ,CAAC,WAAW,mDAAmD;IACvE,QAAQ,CAAC,QAAQ,EAAG,MAAM,CAAU;IAEpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAoB3B;IAEF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAO3B;IAEF,KAAK,CAAC,WAAW,EAAE,WAAW,GAAG,aAAa,EAAE;IA0BhD,OAAO,CAAC,oBAAoB;CAW7B"}
|