← Files Aivana Database EngineerARCHIVED FILE
runtime/sqlSafety.js
1.77 KB · Oct 2, 2026 · 00:34 UTC
const WRITE_KEYWORDS = /\b(alter|create|delete|drop|exec|execute|grant|insert|merge|revoke|truncate|update|xp_cmdshell)\b/i;
const ALWAYS_DANGEROUS = /\b(xp_cmdshell|grant|revoke)\b/i;
const WRITE_LIKE_READ = /\bselect\b[\s\S]+\binto\b/i;
const DANGEROUS_READ_FUNCTIONS = /\b(nextval|setval|pg_advisory_lock|pg_advisory_unlock|dblink_exec)\s*\(/i;
function stripSqlComments(sql) {
return String(sql || "")
.replace(/\/\*[\s\S]*?\*\//g, " ")
.replace(/--[^\r\n]*/g, " ");
}
function hasMultipleStatements(sql) {
const cleaned = stripSqlComments(sql).trim();
const withoutTerminal = cleaned.endsWith(";") ? cleaned.slice(0, -1) : cleaned;
return withoutTerminal.includes(";");
}
function validateSqlSafety(sql, options = {}) {
const statement = String(sql || "").trim();
const violations = [];
if (!statement) {
return { safe: false, violations: ["missing_sql"] };
}
const cleaned = stripSqlComments(statement);
if (hasMultipleStatements(cleaned)) {
violations.push("multiple_statements");
}
const writeAllowed = Boolean(options.allowWrite || options.isMigration);
const dangerousPattern = writeAllowed ? ALWAYS_DANGEROUS : WRITE_KEYWORDS;
if (dangerousPattern.test(cleaned)) {
violations.push("dangerous_keyword");
}
if (!writeAllowed && WRITE_LIKE_READ.test(cleaned)) {
violations.push("write_like_read");
}
if (!writeAllowed && DANGEROUS_READ_FUNCTIONS.test(cleaned)) {
violations.push("dangerous_function");
}
if (options.readOnly !== false && !/^\s*(select|with|explain|show)\b/i.test(cleaned)) {
violations.push("read_statement_required");
}
return {
safe: violations.length === 0,
violations: Array.from(new Set(violations)),
normalizedSql: cleaned,
};
}
module.exports = {
stripSqlComments,
validateSqlSafety,
};
SHA-256: eb9d00a697d045517f6419032125cd9168767dc743bdd3a585c1927969ce574b