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.
53 lines • 2.35 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const rule = {
meta: {
id: 'LOVABLE002',
category: 'security',
severity: 'high',
message: 'Supabase credentials hardcoded in source code',
fix: 'Move to .env file (VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY) and access via import.meta.env',
helpUri: 'https://vitejs.dev/guide/env-and-mode.html',
impact: 'Exposed Supabase credentials in client-side code allow attackers to abuse your API quota and access data if RLS is misconfigured.'
},
impl: {
detect: (content, file, lines) => {
const results = [];
// Pattern 1: Hardcoded Supabase URL
const urlPattern = /(['"`])https:\/\/[a-z0-9-]+\.supabase\.co\1/gi;
let match;
while ((match = urlPattern.exec(content)) !== null) {
const beforeMatch = content.substring(0, match.index);
const lineNumber = beforeMatch.split('\n').length;
const line = lines[lineNumber - 1];
// Check if it's in an env var access (that's OK)
if (!/import\.meta\.env|process\.env|Deno\.env/i.test(line)) {
results.push({
line: lineNumber,
match: match[0],
confidence: 0.95
});
}
}
// Pattern 2: Hardcoded JWT/anon key (eyJ... pattern)
const jwtPattern = /eyJ[A-Za-z0-9._-]{30,}/gi;
while ((match = jwtPattern.exec(content)) !== null) {
const beforeMatch = content.substring(0, match.index);
const lineNumber = beforeMatch.split('\n').length;
const line = lines[lineNumber - 1];
// Check if it's in an env var access (that's OK)
if (!/import\.meta\.env|process\.env|Deno\.env/i.test(line)) {
results.push({
line: lineNumber,
match: match[0].slice(0, 50) + '...',
confidence: 0.95
});
}
}
return results;
},
fileTypes: ['js', 'jsx', 'ts', 'tsx']
}
};
exports.default = rule;
//# sourceMappingURL=LOVABLE002.js.map