HIGH auth bypasssqlite

Auth Bypass in Sqlite

How Auth Bypass Manifests in Sqlite

Authentication bypass in applications that rely on SQLite often stems from improper handling of user‑supplied data when constructing SQL statements. Because SQLite is a lightweight, file‑based engine, developers sometimes concatenate raw input directly into query strings, assuming the simplicity of the database eliminates injection risk. This assumption is false; SQLite’s SQL parser is fully featured and vulnerable to the same classic injection patterns that affect larger RDBMS.

A typical vulnerable pattern looks like this in Python’s sqlite3 module:

# Vulnerable: concatenation of username and password
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)

If an attacker supplies admin' -- as the username, the resulting query becomes:

SELECT * FROM users WHERE username = 'admin' --' AND password = '{password}'

The comment (--) neutralizes the password check, allowing login as admin without knowing the password. SQLite‑specific nuances can amplify the impact:

  • PRAGMA statements: Injecting '; PRAGMA table_info(users);-- can leak schema details.
  • ATTACH DATABASE: An attacker may attach a malicious database file and then read or write data through ATTACH DATABASE '/tmp/evil.db' AS aux;--.
  • SQLite functions: Using hex(), substr(), or like with wildcards can aid blind injection techniques that extract data byte‑by‑byte.
  • Compound queries: UNION SELECT NULL, password, NULL FROM users-- can return password hashes in the same column layout expected by the application.

Because SQLite is frequently embedded in mobile apps, IoT firmware, and desktop tools, the authentication bypass often occurs in login APIs, token‑exchange endpoints, or any service that validates credentials against a local SQLite store before issuing a session token.

Sqlite-Specific Detection

Detecting auth bypass in SQLite‑backed APIs requires probing the unauthenticated surface for injection vectors that manipulate authentication logic. middleBrick performs this automatically as part of its Input Validation and BOLA/IDOR checks, sending a series of crafted payloads and analysing responses for signs of successful bypass.

During a scan, middleBrick will:

  • Submit payloads such as ' OR '1'='1, admin'--, and ' UNION SELECT NULL, password, NULL FROM users-- to login‑like endpoints.
  • Look for changes in HTTP status code (e.g., 200 OK instead of 401 Unauthorized), presence of session tokens, or redirected URLs that indicate a successful login.
  • Detect error messages that reveal SQLite syntax (near "--": syntax error) which can confirm injection points.
  • Perform time‑based blind checks using SQLite’s randomblob() or sleep()‑equivalent constructs (e.g., CASE WHEN (SELECT COUNT(*) FROM users) > 0 THEN randomblob(1000000) END) to infer Boolean responses when error messages are suppressed.
  • Cross‑reference any discovered OpenAPI/Swagger specification to confirm that the affected endpoint expects username/password parameters and map the finding to the Authentication and Input Validation categories.

Example CLI usage to trigger a scan:

middlebrick scan https://api.example.com/login

The tool returns a JSON report that includes a finding such as:

{
  "category": "Input Validation",
  "severity": "high",
  "title": "Potential SQL injection in login endpoint",
  "description": "Payload \"admin'--\" bypassed password check, returning a session token.",
  "remediation": "Use parameterized queries or prepared statements; never concatenate user input into SQL strings."
}

Because middleBrick does not require agents or credentials, the scan can be run against staging or production URLs as part of a CI pipeline, giving developers immediate feedback on SQLite‑specific authentication flaws before they are exploited.

Sqlite-Specific Remediation

The most reliable defense against SQLite authentication bypass is to eliminate string concatenation when building queries. SQLite’s C API and its language bindings support prepared statements with bound parameters, which separate code from data and prevent injection regardless of the input’s content.

Below is a vulnerable Node.js example using the better-sqlite3 library, followed by the fixed version.

// Vulnerable: raw concatenation
const db = require('better-sqlite3')('users.db');
function login(username, password) {
  const sql = `SELECT * FROM users WHERE username = '${username}' AND password = '${password}'`;
  return db.prepare(sql).get();
}

Fixed version using parameterized queries:

// Fixed: use placeholders and bind values
const db = require('better-sqlite3')('users.db');
function login(username, password) {
  const sql = `SELECT * FROM users WHERE username = ? AND password = ?`;
  return db.prepare(sql).get(username, password);
}

The same principle applies in Python’s built‑in sqlite3 module:

# Vulnerable
cursor.execute(f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'")

# Fixed
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))

Additional SQLite‑specific hardening steps:

  • Enable PRAGMA foreign_keys = ON; to enforce referential integrity, reducing the chance that an attached malicious database can corrupt critical tables.
  • Restrict the SQLite file’s filesystem permissions so the application process is the only user that can read/write it; this limits the impact of ATTACH DATABASE attacks.
  • Consider using sqlite3_mprintf with the %q qualifier when building dynamic queries in C, which properly escapes string literals.
  • Apply application‑level authentication checks (e.g., verify a JWT or session token) after the database lookup, so even if a SQL flaw returns a row, the token validation will still fail for unauthorized users.
  • Regularly update the SQLite library to the latest patch version; while the core engine is stable, newer releases may include hardening features such as stricter parsing of comment sequences.

By adopting parameterized queries and limiting database file access, developers close the most common injection paths that lead to authentication bypass in SQLite‑backed services.

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

Can middleBrick detect SQLite auth bypass if the application uses ORM frameworks?
Yes. middleBrick treats the API as a black box and sends injection payloads to the exposed endpoints. Regardless of whether the backend uses an ORM, raw SQLite, or a query builder, any point where user input reaches the SQLite engine without proper parameterization will be reflected in the response patterns that middleBrick analyses.
Is it safe to rely on SQLite’s built‑in escaping functions for authentication queries?
Relying on manual escaping (e.g., SQLite’s sqlite3_mprintf with %q) is error‑prone and easy to miss edge cases. The recommended approach is to use prepared statements with bound parameters, which let the SQLite engine handle escaping automatically and eliminate the risk of bypass.