Skip to content

Commit 5bfb74d

Browse files
Fix remaining 8 code scanning security vulnerabilities
Fixed all 8 remaining security issues identified by GitHub code scanning: 1. Clear-text logging (CWE-312) - Already fixed in previous commit 2. CORS misconfiguration (CWE-942) - Fixed credential transfer with dynamic origins 3. Incomplete sanitization in AutoCommitManager - Properly escape all regex special chars 4. Incomplete sanitization in GitHubSecretManager - Use global replace for wildcards 5. Incomplete sanitization in EnvironmentPropagator - Escape backslashes properly 6. Bad HTML filtering in InputValidator - Handle script tags with spaces Security improvements: - SharedContextServer: Only allow credentials for whitelisted origins - AutoCommitManager: Complete regex escaping including backslashes - GitHubSecretManager: Use /\*/g for global wildcard replacement - EnvironmentPropagator: Escape backslashes before quotes in values - InputValidator: Improved XSS detection with flexible tag matching
1 parent a3af390 commit 5bfb74d

File tree

5 files changed

+28
-10
lines changed

5 files changed

+28
-10
lines changed

src/context/SharedContextServer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,16 @@ export class SharedContextServer extends EventEmitter {
174174

175175
if (allowedOrigins.includes(origin)) {
176176
res.setHeader('Access-Control-Allow-Origin', origin);
177+
res.setHeader('Access-Control-Allow-Credentials', 'true');
177178
} else if (origin.startsWith('http://localhost:') || origin.startsWith('http://127.0.0.1:')) {
178179
// Allow any localhost port for development flexibility
179180
res.setHeader('Access-Control-Allow-Origin', origin);
181+
// Don't allow credentials for dynamic origins
182+
res.setHeader('Access-Control-Allow-Credentials', 'false');
180183
}
181184

182185
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
183186
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
184-
res.setHeader('Access-Control-Allow-Credentials', 'true');
185187

186188
if (method === 'OPTIONS') {
187189
res.writeHead(200);

src/database/EnvironmentPropagator.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,8 +724,10 @@ export class EnvironmentPropagator {
724724
*/
725725
private quoteValue(value: string): string {
726726
// Quote if contains spaces or special characters
727-
if (value.includes(' ') || value.includes('\n') || value.includes('\t') || value.includes('"')) {
728-
return `"${value.replace(/"/g, '\\"')}"`;
727+
if (value.includes(' ') || value.includes('\n') || value.includes('\t') || value.includes('"') || value.includes('\\')) {
728+
// Escape backslashes first, then quotes
729+
const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
730+
return `"${escaped}"`;
729731
}
730732
return value;
731733
}

src/github/GitHubSecretManager.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ export class GitHubSecretManager {
393393
if (options.include && options.include.length > 0) {
394394
filtered = filtered.filter(entry =>
395395
options.include!.some(pattern =>
396-
entry.key.match(new RegExp(pattern.replace('*', '.*')))
396+
entry.key.match(new RegExp(pattern.replace(/\*/g, '.*')))
397397
)
398398
);
399399
}
@@ -402,7 +402,7 @@ export class GitHubSecretManager {
402402
if (options.exclude && options.exclude.length > 0) {
403403
filtered = filtered.filter(entry =>
404404
!options.exclude!.some(pattern =>
405-
entry.key.match(new RegExp(pattern.replace('*', '.*')))
405+
entry.key.match(new RegExp(pattern.replace(/\*/g, '.*')))
406406
)
407407
);
408408
}
@@ -419,7 +419,7 @@ export class GitHubSecretManager {
419419

420420
filtered = filtered.filter(entry =>
421421
!commonNonSecrets.some(pattern =>
422-
entry.key.match(new RegExp(pattern.replace('*', '.*')))
422+
entry.key.match(new RegExp(pattern.replace(/\*/g, '.*')))
423423
)
424424
);
425425

src/protection/AutoCommitManager.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,22 @@ export class AutoCommitManager {
204204
}
205205

206206
private matchesPattern(filePath: string, pattern: string): boolean {
207-
// Convert glob pattern to regex
207+
// Convert glob pattern to regex - escape special characters properly
208208
const regexPattern = pattern
209+
.replace(/\\/g, '\\\\') // Escape backslashes first
209210
.replace(/\./g, '\\.')
210211
.replace(/\*/g, '.*')
211-
.replace(/\?/g, '.');
212+
.replace(/\?/g, '.')
213+
.replace(/\[/g, '\\[')
214+
.replace(/\]/g, '\\]')
215+
.replace(/\(/g, '\\(')
216+
.replace(/\)/g, '\\)')
217+
.replace(/\^/g, '\\^')
218+
.replace(/\$/g, '\\$')
219+
.replace(/\+/g, '\\+')
220+
.replace(/\{/g, '\\{')
221+
.replace(/\}/g, '\\}')
222+
.replace(/\|/g, '\\|');
212223

213224
const regex = new RegExp(`^${regexPattern}$`);
214225
return regex.test(filePath) || regex.test(path.basename(filePath));

src/validation/InputValidator.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,14 @@ export class InputValidator {
3232

3333
// XSS patterns
3434
private static readonly XSS_PATTERNS = [
35-
/<script[^>]*>.*?<\/script>/gi,
36-
/<iframe[^>]*>.*?<\/iframe>/gi,
35+
/<script[^>]*>.*?<\/\s*script\s*>/gi, // Matches </script> with optional spaces
36+
/<iframe[^>]*>.*?<\/\s*iframe\s*>/gi, // Matches </iframe> with optional spaces
3737
/javascript:/gi,
3838
/on\w+\s*=/gi,
3939
/<img[^>]*onerror[^>]*>/gi,
40+
/<style[^>]*>.*?<\/\s*style\s*>/gi, // Also check style tags
41+
/<object[^>]*>.*?<\/\s*object\s*>/gi, // Check object tags
42+
/<embed[^>]*>/gi, // Check embed tags
4043
];
4144

4245
/**

0 commit comments

Comments
 (0)