vibe-guard
Version:
🛡️ Vibe-Guard Security Scanner - Catch security issues before they catch you!
95 lines • 5.12 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqlInjectionRule = void 0;
const types_1 = require("../types");
class SqlInjectionRule extends types_1.BaseRule {
constructor() {
super(...arguments);
this.name = 'sql-injection';
this.description = 'Detects potential SQL injection vulnerabilities';
this.severity = 'high';
this.sqlInjectionPatterns = [
// String concatenation in SQL
{ pattern: /(?:query|sql|execute)\s*\(\s*['"`][^'"`]*['"`]\s*\+\s*[^'"`\s)]+/gi, type: 'String concatenation in SQL query' },
{ pattern: /['"`]SELECT\s+[^'"`]*['"`]\s*\+\s*[^'"`\s)]+/gi, type: 'SELECT query with concatenation' },
{ pattern: /['"`]INSERT\s+[^'"`]*['"`]\s*\+\s*[^'"`\s)]+/gi, type: 'INSERT query with concatenation' },
{ pattern: /['"`]UPDATE\s+[^'"`]*['"`]\s*\+\s*[^'"`\s)]+/gi, type: 'UPDATE query with concatenation' },
{ pattern: /['"`]DELETE\s+[^'"`]*['"`]\s*\+\s*[^'"`\s)]+/gi, type: 'DELETE query with concatenation' },
// Template literals with variables
{ pattern: /`SELECT\s+[^`]*\$\{[^}]+\}[^`]*`/gi, type: 'Template literal SQL with variables' },
{ pattern: /`INSERT\s+[^`]*\$\{[^}]+\}[^`]*`/gi, type: 'Template literal INSERT with variables' },
{ pattern: /`UPDATE\s+[^`]*\$\{[^}]+\}[^`]*`/gi, type: 'Template literal UPDATE with variables' },
{ pattern: /`DELETE\s+[^`]*\$\{[^}]+\}[^`]*`/gi, type: 'Template literal DELETE with variables' },
// String formatting in SQL
{ pattern: /(?:query|sql)\s*=\s*['"`][^'"`]*%s[^'"`]*['"`]\s*%\s*\(/gi, type: 'Python string formatting in SQL' },
{ pattern: /(?:query|sql)\s*=\s*f['"`][^'"`]*\{[^}]+\}[^'"`]*['"`]/gi, type: 'Python f-string in SQL' },
{ pattern: /String\.format\s*\(\s*['"`][^'"`]*\{[^}]*\}[^'"`]*['"`]/gi, type: 'Java String.format in SQL' },
// Direct variable insertion
{ pattern: /WHERE\s+[^'"`\s]+\s*=\s*['"`]?\s*\+\s*[^'"`\s)]+/gi, type: 'WHERE clause with concatenation' },
{ pattern: /WHERE\s+[^'"`\s]+\s*=\s*\$\{[^}]+\}/gi, type: 'WHERE clause with template variable' },
// Framework-specific patterns
{ pattern: /\.query\s*\(\s*['"`][^'"`]*['"`]\s*\+/gi, type: 'Database query with concatenation' },
{ pattern: /\.exec\s*\(\s*['"`][^'"`]*['"`]\s*\+/gi, type: 'Database exec with concatenation' },
{ pattern: /\.raw\s*\(\s*['"`][^'"`]*['"`]\s*\+/gi, type: 'Raw SQL query with concatenation' },
// ORM unsafe patterns
{ pattern: /\.where\s*\(\s*['"`][^'"`]*['"`]\s*\+/gi, type: 'ORM where clause with concatenation' },
{ pattern: /\.whereRaw\s*\(\s*['"`][^'"`]*['"`]\s*\+/gi, type: 'ORM raw where with concatenation' }
];
this.safePatterns = [
// Parameterized queries
/\?\s*,/g, // Question mark parameters
/\$\d+/g, // Numbered parameters
/:\w+/g, // Named parameters
/prepare/i,
/bind/i,
/params/i,
/placeholder/i
];
}
check(fileContent) {
const issues = [];
for (const { pattern, type } of this.sqlInjectionPatterns) {
const matches = this.findMatches(fileContent.content, pattern);
for (const { line, column, lineContent } of matches) {
// Skip if the line contains safe parameterization patterns
if (this.hasSafeParameterization(lineContent)) {
continue;
}
// Skip if it's in a comment or test file
if (this.isCommentOrTest(lineContent, fileContent.path)) {
continue;
}
issues.push(this.createIssue(fileContent.path, line, column, lineContent, `Potential SQL injection vulnerability: ${type}`, `Use parameterized queries or prepared statements instead of string concatenation. Replace concatenation with placeholders (?, $1, :param) and pass values as parameters.`));
}
}
return issues;
}
hasSafeParameterization(line) {
return this.safePatterns.some(pattern => pattern.test(line));
}
isCommentOrTest(line, filePath) {
// Check if line is a comment
const commentPatterns = [
/^\s*\/\//, // JavaScript comment
/^\s*#/, // Python/Shell comment
/^\s*--/, // SQL comment
/^\s*\*/ // Multi-line comment
];
if (commentPatterns.some(pattern => pattern.test(line))) {
return true;
}
// Check if it's a test file
const testPatterns = [
/test/i,
/spec/i,
/\.test\./i,
/\.spec\./i,
/__tests__/i,
/tests\//i,
/spec\//i
];
return testPatterns.some(pattern => pattern.test(filePath));
}
}
exports.SqlInjectionRule = SqlInjectionRule;
//# sourceMappingURL=sql-injection.js.map