ubon
Version:
Security scanner for AI-generated apps (Cursor, Lovable, Windsurf, v0). Catches hardcoded secrets, prompt injection, hallucinated imports, Server Actions / Edge runtime mistakes, and the vibe-coded vulnerabilities traditional linters miss.
71 lines • 3.14 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReactSecurityScanner = void 0;
const glob_1 = require("glob");
const fs_1 = require("fs");
const rules_1 = require("../rules");
class ReactSecurityScanner {
name = 'React Security Scanner';
async scan(options) {
const results = [];
const files = await (0, glob_1.glob)('**/*.{jsx,tsx}', {
cwd: options.directory,
ignore: ['node_modules/**', 'dist/**', 'build/**', '.next/**', 'examples/**']
});
// React-specific security rules
const reactRuleIds = [
'TAILWIND001' // Dynamic className Injection
];
for (const file of files) {
try {
const filePath = `${options.directory}/${file}`;
const content = (0, fs_1.readFileSync)(filePath, 'utf-8');
const lines = content.split('\n');
// Apply each React security rule
for (const ruleId of reactRuleIds) {
const rule = (0, rules_1.getRule)(ruleId);
if (!rule || !rule.impl.detect)
continue;
// Check file type restrictions
if (rule.impl.fileTypes) {
const fileExt = file.split('.').pop() || '';
if (!rule.impl.fileTypes.includes(fileExt))
continue;
}
// Run detection
const detections = rule.impl.detect(content, file, lines);
// Convert detections to ScanResults
for (const detection of detections) {
const line = lines[detection.line - 1] || '';
results.push({
type: rule.meta.severity === 'high' ? 'error' : 'warning',
category: rule.meta.category,
message: rule.meta.message,
file,
line: detection.line,
range: {
startLine: detection.line,
startColumn: 1,
endLine: detection.line,
endColumn: Math.max(1, line.length)
},
severity: rule.meta.severity,
ruleId: rule.meta.id,
confidence: detection.confidence || 0.80,
match: detection.match,
fix: rule.meta.fix,
helpUri: rule.meta.helpUri,
...(detection.fixEdits ? { fixEdits: detection.fixEdits } : {})
});
}
}
}
catch (error) {
// Skip files that can't be read
}
}
return results;
}
}
exports.ReactSecurityScanner = ReactSecurityScanner;
//# sourceMappingURL=react-security-scanner.js.map