Open-source runtime verification for AI, licensed under Apache-2.0.
QWED
Contact

Type to search pages, engines and advisories.

    Looking for API details?Search the docs

    GHSA-q5g6-6cw2-cjm3

    SQLVerifier admits a tautology hidden in a MySQL executable comment, and queries on tables outside the declared schema

    mediumPublished 13 October 2026

    Impact

    SQLVerifier.verify_sql admits two kinds of query that its own checks would reject in plain form. This affects every caller that gates on admission_decision, including POST /verify/sql.

    1. MySQL executable comments. With dialect="mysql", a tautology inside /*!NNNNN ... */ is not seen, and the query comes back VERIFIED, is_valid: true, ADMIT, with no issues. The same query without the comment is caught as injection_tautology. MySQL and MariaDB execute the contents of executable comments, so the query returns every row. This is the same class of bug as GHSA-q8r4-6gpp-5fx2 in qwed-finance's QueryGuard.
    2. Tables outside the schema. When schema_ddl declares the allowed tables, a query on another table is recorded as schema_table_missing, but is_valid stays true and admission is ADMIT. The same applies to a UNION that reads an undeclared table. The schema check reports the violation without affecting the decision.

    Reproduction (qwed 7.2.2, main 3e91f12)

    from qwed_new.core.sql_verifier import SQLVerifier
    from qwed_new.core.diagnostics import admission_decision
    
    ddl = "CREATE TABLE users (id INT, name TEXT, role TEXT)"
    cases = [
        ("SELECT * FROM users WHERE id = 1 /*!50000 OR 1=1 */", "mysql"),           # VERIFIED True ADMIT, issues []
        ("SELECT * FROM users WHERE id = 1 OR 1=1", "mysql"),                       # VERIFIED False BLOCKED, injection_tautology
        ("SELECT id FROM secrets", "postgres"),                                     # VERIFIED True ADMIT, schema_table_missing
        ("SELECT id FROM users WHERE id = 1 UNION SELECT id FROM secrets", "postgres"),  # VERIFIED True ADMIT
    ]
    for query, dialect in cases:
        r = SQLVerifier().verify_sql(query, ddl, dialect)
        print(r.status.value, r.developer_fields["is_valid"], admission_decision(r).value)
    

    Patches

    Fixed in 7.2.3:

    • MySQL and MariaDB executable comments (/*! ... */, /*!NNNNN ... */, /*M! ... */) are expanded before analysis, whatever the declared dialect, so SQL inside them is checked. developer_fields.executable_comments_expanded records when this happened.
    • With schema_ddl, a table outside the declared schema is an admission failure: is_valid: false, constraint sql_verifier.schema_violation. Names defined by the query itself (CTEs) are not treated as tables; without schema_ddl, tables are not checked.

    Workarounds

    Until you upgrade:

    • Reject queries that contain /*! before calling verify_sql.
    • Treat schema_table_missing in developer_fields.issues as a reason not to run the query.

    Credit

    Found by the soundness eval (#439) while writing its SQL cases.

    Affected and fixed

    Package
    qwed
    Affected
    <= 7.2.2
    Fixed in
    7.2.3
    Severity
    medium
    Weakness
    CWE-184 Incomplete List of Disallowed Inputs
    CWE-436 Interpretation Conflict
    CWE-863 Incorrect Authorization
    View on GitHub

    All advisories