FlowiseAI/Flowise · critical · Error

Invalid SQL statement: load_extension is not allowed

Error message

Invalid SQL statement: load_extension is not allowed

What it means

Thrown by assertReadOnlySqlStatement (packages/components/src/validator.ts:397) when the statement contains 'load_extension(' (case-insensitive). SQLite's load_extension lets a query load arbitrary native code into the process; even though the statement may start with SELECT, this guard blocks the function call to prevent code execution via a malicious DB/LLM.

Source

Thrown at packages/components/src/validator.ts:397

export const assertReadOnlySqlStatement = (sql: string): void => {
    if (!sql || typeof sql !== 'string') {
        throw new Error('Invalid SQL statement: statement is required and must be a string')
    }

    let trimmed = sql.trim()
    // Strip at most one trailing semicolon (+ trailing whitespace)
    trimmed = trimmed.replace(/;\s*$/, '')

    if (trimmed.includes(';')) {
        throw new Error('Invalid SQL statement: multiple statements are not allowed')
    }

    if (!/^(SELECT|WITH)\b/i.test(trimmed)) {
        throw new Error('Invalid SQL statement: only read-only SELECT/WITH statements are allowed')
    }

    if (/load_extension\s*\(/i.test(trimmed)) {
        throw new Error('Invalid SQL statement: load_extension is not allowed')
    }
}

/**
 * Sanitize a file name to prevent path traversal attacks.
 * Strips common storage prefixes, extracts the basename, runs it through
 * the `sanitize-filename` package, and rejects anything that still looks unsafe.
 *
 * @param {string} name The file name to sanitize
 */
export const sanitizeFileName = (name: string): string => {
    if (!name || typeof name !== 'string') {
        throw new Error('Invalid file name: name is required')
    }
    // Strip the FILE-STORAGE:: prefix if present
    let stripped = name.replace(/^FILE-STORAGE::/, '')
    // Decode percent-encoded traversal sequences before basename extraction
    try {

View on GitHub (pinned to abe4a8601a)

Solutions

  1. Remove the load_extension call — Flowise does not allow it.
  2. Treat any LLM output containing load_extension as a prompt-injection attempt and reject the turn.
  3. Only ingest .sqlite files from trusted sources.
  4. Compile SQLite without load_extension support for defense-in-depth.

Example fix

// before
sql = "SELECT load_extension('/tmp/evil')"

// after
sql = 'SELECT name FROM sqlite_master WHERE type = \'table\''   // benign introspection
Defensive patterns

Strategy: validation

Validate before calling

if (/load_extension\s*\(/i.test(String(sql ?? ''))) throw new Error('load_extension rejected (possible prompt injection)');
assertReadOnlySqlStatement(sql);

Type guard

const isFreeOfLoadExtension = (s: unknown): s is string => typeof s === 'string' && !/load_extension\s*\(/i.test(s);

Try / catch

try { assertReadOnlySqlStatement(sql) } catch (e) { if (e instanceof Error && /load_extension/.test(e.message)) { /* treat as prompt injection: abort turn */ throw new SecurityError('load_extension attempt blocked') } else throw e }

Prevention

When it happens

Trigger: The SQL contains a call like "SELECT load_extension('/tmp/evil')" — typically from a malicious LLM response or an attacker-controlled .sqlite file with crafted views/triggers that emit such SQL.

Common situations: Security testing/fuzzing of the chain; loading a DB file from an untrusted source; a prompt-injection payload crafting the call.

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/1197257d58f763ce. Report an issue: GitHub.