CVE-2026-54760
Langroid: SQLChatAgent dangerous-function blocklist can be bypassed with quoted or schema-qualified pg_read_file calls
Langroid is a framework for building large-language-model-powered applications. Prior to version 0.65.1, the SQLChatAgent SQL-injection mitigation, with default allow_dangerous_operations=False, combines a raw-text regex blocklist (_DANGEROUS_SQL_PATTERNS) with a sqlglot SELECT-only statement allowlist. The blocklist entries that target callable functions require the function name to be immediately followed by \s*\(. PostgreSQL accepts the same call with the name separated from ( by a quoted identifier, an inline comment, or schema qualification. These forms evade the regex, still parse as SELECT, and execute the same PostgreSQL function. This restores the pg_read_file server-side file-read primitive that the prior CVE-2026-25879 / GHSA-pmch-g965-grmr fix was meant to block: the parent advisory fixed a missing pg_read_file blocklist entry, while this report shows that the added regex is bypassable. Version 0.65.1 fixes the issue.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
9.3
Langroid: SQLChatAgent dangerous-function blocklist can be bypassed with quoted or schema-qualified pg_read_file calls
Langroid is a framework for building large-language-model-powered applications. Prior to version 0.65.1, the SQLChatAgent SQL-injection mitigation, with default allow_dangerous_operations=False, combines a raw-text regex blocklist (_DANGEROUS_SQL_PATTERNS) with a sqlglot SELECT-only statement allowlist. The blocklist entries that target callable functions require the function name to be immediately followed by \s*\(. PostgreSQL accepts the same call with the name separated from ( by a quoted identifier, an inline comment, or schema qualification. These forms evade the regex, still parse as SELECT, and execute the same PostgreSQL function. This restores the pg_read_file server-side file-read primitive that the prior CVE-2026-25879 / GHSA-pmch-g965-grmr fix was meant to block: the parent advisory fixed a missing pg_read_file blocklist entry, while this report shows that the added regex is bypassable. Version 0.65.1 fixes the issue.
- Record
CVE-2026-54760- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-22, CWE-89
- Updated
- 2026-11-02
EUVDEUVD-2026-42754
9.3
Langroid is a framework for building large-language-model-powered applications. Prior to version 0.65.1, the SQLChatAgent SQL-injection mitigation, with default allow_dangerous_operations=False, combines a raw-text regex blocklist (_DANGEROUS_SQL_PATTERNS) with a sqlglot SELECT-only statement allowlist. The blocklist entries that target callable functions require the function name to be immediately followed by \s*\(. PostgreSQL accepts the same call with the name separated from ( by a quoted identifier, an inline comment, or schema qualification. These forms evade the regex, still parse as SELECT, and execute the same PostgreSQL function. This restores the pg_read_file server-side file-read primitive that the prior CVE-2026-25879 / GHSA-pmch-g965-grmr fix was meant to block: the parent advisory fixed a missing pg_read_file blocklist entry, while this report shows that the added regex is bypassable. Version 0.65.1 fixes the issue.
- Record
EUVD-2026-42754- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-6xc5-4r68-67fc
9.3
Langroid: SQLChatAgent dangerous-function blocklist can be bypassed with quoted or schema-qualified pg_read_file calls
SQLChatAgent _validate_query dangerous-pattern regex is bypassable via quoted/commented/qualified function names
Summary
The SQLChatAgent SQL-injection mitigation, with default allow_dangerous_operations=False, combines a raw-text regex blocklist (_DANGEROUS_SQL_PATTERNS) with a sqlglot SELECT-only statement allowlist. The blocklist entries that target callable functions require the function name to be immediately followed by \s*\(.
PostgreSQL accepts the same call with the name separated from ( by a quoted identifier, an inline comment, or schema qualification. These forms evade the regex, still parse as SELECT, and execute the same PostgreSQL function. This restores the pg_read_file server-side file-read primitive that the prior CVE-2026-25879 / GHSA-pmch-g965-grmr fix was meant to block: the parent advisory fixed a missing pg_read_file blocklist entry, while this report shows that the added regex is bypassable.
Affected Code
Tested against current main commit:
6e8e7b2bb23ec04c1c25be479f16b8cc9a4f8796
The current source still contains:
re.compile(r"\bpg_(read|stat|ls|current_logfile)[A-Za-z0-9_]*\s*\(", re.IGNORECASE)
_validate_query checks the raw query against _DANGEROUS_SQL_PATTERNS, then parses with sqlglot and allows SELECT statements. The dangerous-call check is raw text, not normalized AST function-name matching.
Root Cause
The current mitigation treats dangerous PostgreSQL function calls as a raw-text regex problem. The regex requires the pg_... function token to be followed directly by optional whitespace and (, but PostgreSQL accepts equivalent calls through quoted identifiers, comments, and schema-qualified names. Because _validate_query only uses sqlglot to enforce the top-level statement type, those normalized function names are never checked after parsing.
Auth Boundary
The boundary is the default SQLChatAgent safety policy between attacker-influenced SQL generation and database operations that can read server-side files. With allow_dangerous_operations=False, a user or prompt that influences generated SQL should not be able to bypass the guard and execute PostgreSQL file-read functions such as pg_read_file.
This is not a new unauthenticated endpoint or product-wide SQL injection; it applies when untrusted user content can influence SQLChatAgent's generated SQL.
Reproduction
The local harness uses the current sql_chat_agent.py, extracts the real shipped dangerous regex list, validates the queries with real sqlglot==30.8.0, then executes the accepted bypasses against a local throwaway PostgreSQL 16 container.
Transcript excerpt:
CONTROL "SELECT pg_read_file('/etc/passwd')" -> REJECTED: matches '\\bpg_(read|stat|ls|current_logfile)[A-Za-z0-9_]*\\s*\\('
BYPASS 'SELECT "pg_read_file"(\'/etc/passwd\')' -> ALLOWED (validator returned None -> would execute)
BYPASS "SELECT pg_read_file/**/('/etc/passwd')" -> ALLOWED (validator returned None -> would execute)
BYPASS 'SELECT pg_catalog."pg_read_file"(\'/etc/passwd\')' -> ALLOWED (validator returned None -> would execute)
=== Part B: real PostgreSQL execution of the bypass ===
connected; is_superuser=t
executed bypass 'SELECT "pg_read_file"(\'<file>\')' -> file contents returned: 'LANGROID_SAFE_MARKER_...'
executed bypass "SELECT pg_read_file/**/('<file>')" -> file contents returned: 'LANGROID_SAFE_MARKER_...'
executed bypass 'SELECT pg_catalog."pg_read_file"(\'<file>\')' -> file contents returned: 'LANGROID_SAFE_MARKER_...'
RESULT: VULNERABLE
The control query is blocked by the current regex, while all three equivalent PostgreSQL forms are allowed by the validator and return the mounted proof file contents from a real PostgreSQL server. The LANGROID_SAFE_MARKER_... value is a harmless marker generated inside the throwaway local container for this proof.
Impact
On a deployment using SQLChatAgent against PostgreSQL with a role able to…
- Record
GHSA-6xc5-4r68-67fc- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-22, CWE-89
- Updated
- 2026-11-02
NVD
9.3
Langroid is a framework for building large-language-model-powered applications. Prior to version 0.65.1, the SQLChatAgent SQL-injection mitigation, with default allow_dangerous_operations=False, combines a raw-text regex blocklist (_DANGEROUS_SQL_PATTERNS) with a sqlglot SELECT-only statement allowlist. The blocklist entries that target callable functions require the function name to be immediately followed by \s*\(. PostgreSQL accepts the same call with the name separated from ( by a quoted identifier, an inline comment, or schema qualification. These forms evade the regex, still parse as SELECT, and execute the same PostgreSQL function. This restores the pg_read_file server-side file-read primitive that the prior CVE-2026-25879 / GHSA-pmch-g965-grmr fix was meant to block: the parent advisory fixed a missing pg_read_file blocklist entry, while this report shows that the added regex is bypassable. Version 0.65.1 fixes the issue.
- Record
CVE-2026-54760- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - Weakness
- CWE-22, CWE-89
- Updated
- 2026-11-02
OSV
9.3
Langroid: SQLChatAgent dangerous-function blocklist can be bypassed with quoted or schema-qualified pg_read_file calls
Langroid is a framework for building large-language-model-powered applications. Prior to version 0.65.1, the SQLChatAgent SQL-injection mitigation, with default allow_dangerous_operations=False, combines a raw-text regex blocklist (_DANGEROUS_SQL_PATTERNS) with a sqlglot SELECT-only statement allowlist. The blocklist entries that target callable functions require the function name to be immediately followed by \s*\(. PostgreSQL accepts the same call with the name separated from ( by a quoted identifier, an inline comment, or schema qualification. These forms evade the regex, still parse as SELECT, and execute the same PostgreSQL function. This restores the pg_read_file server-side file-read primitive that the prior CVE-2026-25879 / GHSA-pmch-g965-grmr fix was meant to block: the parent advisory fixed a missing pg_read_file blocklist entry, while this report shows that the added regex is bypassable. Version 0.65.1 fixes the issue.
- Record
CVE-2026-54760- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-22, CWE-89
- Updated
- 2026-11-02
OSVGHSA-6xc5-4r68-67fc
9.3
Langroid: SQLChatAgent dangerous-function blocklist can be bypassed with quoted or schema-qualified pg_read_file calls
SQLChatAgent _validate_query dangerous-pattern regex is bypassable via quoted/commented/qualified function names
Summary
The SQLChatAgent SQL-injection mitigation, with default allow_dangerous_operations=False, combines a raw-text regex blocklist (_DANGEROUS_SQL_PATTERNS) with a sqlglot SELECT-only statement allowlist. The blocklist entries that target callable functions require the function name to be immediately followed by \s*\(.
PostgreSQL accepts the same call with the name separated from ( by a quoted identifier, an inline comment, or schema qualification. These forms evade the regex, still parse as SELECT, and execute the same PostgreSQL function. This restores the pg_read_file server-side file-read primitive that the prior CVE-2026-25879 / GHSA-pmch-g965-grmr fix was meant to block: the parent advisory fixed a missing pg_read_file blocklist entry, while this report shows that the added regex is bypassable.
Affected Code
Tested against current main commit:
6e8e7b2bb23ec04c1c25be479f16b8cc9a4f8796
The current source still contains:
re.compile(r"\bpg_(read|stat|ls|current_logfile)[A-Za-z0-9_]*\s*\(", re.IGNORECASE)
_validate_query checks the raw query against _DANGEROUS_SQL_PATTERNS, then parses with sqlglot and allows SELECT statements. The dangerous-call check is raw text, not normalized AST function-name matching.
Root Cause
The current mitigation treats dangerous PostgreSQL function calls as a raw-text regex problem. The regex requires the pg_... function token to be followed directly by optional whitespace and (, but PostgreSQL accepts equivalent calls through quoted identifiers, comments, and schema-qualified names. Because _validate_query only uses sqlglot to enforce the top-level statement type, those normalized function names are never checked after parsing.
Auth Boundary
The boundary is the default SQLChatAgent safety policy between attacker-influenced SQL generation and database operations that can read server-side files. With allow_dangerous_operations=False, a user or prompt that influences generated SQL should not be able to bypass the guard and execute PostgreSQL file-read functions such as pg_read_file.
This is not a new unauthenticated endpoint or product-wide SQL injection; it applies when untrusted user content can influence SQLChatAgent's generated SQL.
Reproduction
The local harness uses the current sql_chat_agent.py, extracts the real shipped dangerous regex list, validates the queries with real sqlglot==30.8.0, then executes the accepted bypasses against a local throwaway PostgreSQL 16 container.
Transcript excerpt:
CONTROL "SELECT pg_read_file('/etc/passwd')" -> REJECTED: matches '\\bpg_(read|stat|ls|current_logfile)[A-Za-z0-9_]*\\s*\\('
BYPASS 'SELECT "pg_read_file"(\'/etc/passwd\')' -> ALLOWED (validator returned None -> would execute)
BYPASS "SELECT pg_read_file/**/('/etc/passwd')" -> ALLOWED (validator returned None -> would execute)
BYPASS 'SELECT pg_catalog."pg_read_file"(\'/etc/passwd\')' -> ALLOWED (validator returned None -> would execute)
=== Part B: real PostgreSQL execution of the bypass ===
connected; is_superuser=t
executed bypass 'SELECT "pg_read_file"(\'<file>\')' -> file contents returned: 'LANGROID_SAFE_MARKER_...'
executed bypass "SELECT pg_read_file/**/('<file>')" -> file contents returned: 'LANGROID_SAFE_MARKER_...'
executed bypass 'SELECT pg_catalog."pg_read_file"(\'<file>\')' -> file contents returned: 'LANGROID_SAFE_MARKER_...'
RESULT: VULNERABLE
The control query is blocked by the current regex, while all three equivalent PostgreSQL forms are allowed by the validator and return the mounted proof file contents from a real PostgreSQL server. The LANGROID_SAFE_MARKER_... value is a harmless marker generated inside the throwaway local container for this proof.
Impact
On a deployment using SQLChatAgent against PostgreSQL with a role able to…
- Record
GHSA-6xc5-4r68-67fc- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-22, CWE-89
- Updated
- 2026-11-02
OSVPYSEC-2026-2577
9.3
Langroid: SQLChatAgent dangerous-function blocklist can be bypassed with quoted or schema-qualified pg_read_file calls
SQLChatAgent _validate_query dangerous-pattern regex is bypassable via quoted/commented/qualified function names
Summary
The SQLChatAgent SQL-injection mitigation, with default allow_dangerous_operations=False, combines a raw-text regex blocklist (_DANGEROUS_SQL_PATTERNS) with a sqlglot SELECT-only statement allowlist. The blocklist entries that target callable functions require the function name to be immediately followed by \s*\(.
PostgreSQL accepts the same call with the name separated from ( by a quoted identifier, an inline comment, or schema qualification. These forms evade the regex, still parse as SELECT, and execute the same PostgreSQL function. This restores the pg_read_file server-side file-read primitive that the prior CVE-2026-25879 / GHSA-pmch-g965-grmr fix was meant to block: the parent advisory fixed a missing pg_read_file blocklist entry, while this report shows that the added regex is bypassable.
Affected Code
Tested against current main commit:
6e8e7b2bb23ec04c1c25be479f16b8cc9a4f8796
The current source still contains:
re.compile(r"\bpg_(read|stat|ls|current_logfile)[A-Za-z0-9_]*\s*\(", re.IGNORECASE)
_validate_query checks the raw query against _DANGEROUS_SQL_PATTERNS, then parses with sqlglot and allows SELECT statements. The dangerous-call check is raw text, not normalized AST function-name matching.
Root Cause
The current mitigation treats dangerous PostgreSQL function calls as a raw-text regex problem. The regex requires the pg_... function token to be followed directly by optional whitespace and (, but PostgreSQL accepts equivalent calls through quoted identifiers, comments, and schema-qualified names. Because _validate_query only uses sqlglot to enforce the top-level statement type, those normalized function names are never checked after parsing.
Auth Boundary
The boundary is the default SQLChatAgent safety policy between attacker-influenced SQL generation and database operations that can read server-side files. With allow_dangerous_operations=False, a user or prompt that influences generated SQL should not be able to bypass the guard and execute PostgreSQL file-read functions such as pg_read_file.
This is not a new unauthenticated endpoint or product-wide SQL injection; it applies when untrusted user content can influence SQLChatAgent's generated SQL.
Reproduction
The local harness uses the current sql_chat_agent.py, extracts the real shipped dangerous regex list, validates the queries with real sqlglot==30.8.0, then executes the accepted bypasses against a local throwaway PostgreSQL 16 container.
Transcript excerpt:
CONTROL "SELECT pg_read_file('/etc/passwd')" -> REJECTED: matches '\\bpg_(read|stat|ls|current_logfile)[A-Za-z0-9_]*\\s*\\('
BYPASS 'SELECT "pg_read_file"(\'/etc/passwd\')' -> ALLOWED (validator returned None -> would execute)
BYPASS "SELECT pg_read_file/**/('/etc/passwd')" -> ALLOWED (validator returned None -> would execute)
BYPASS 'SELECT pg_catalog."pg_read_file"(\'/etc/passwd\')' -> ALLOWED (validator returned None -> would execute)
=== Part B: real PostgreSQL execution of the bypass ===
connected; is_superuser=t
executed bypass 'SELECT "pg_read_file"(\'<file>\')' -> file contents returned: 'LANGROID_SAFE_MARKER_...'
executed bypass "SELECT pg_read_file/**/('<file>')" -> file contents returned: 'LANGROID_SAFE_MARKER_...'
executed bypass 'SELECT pg_catalog."pg_read_file"(\'<file>\')' -> file contents returned: 'LANGROID_SAFE_MARKER_...'
RESULT: VULNERABLE
The control query is blocked by the current regex, while all three equivalent PostgreSQL forms are allowed by the validator and return the mounted proof file contents from a real PostgreSQL server. The LANGROID_SAFE_MARKER_... value is a harmless marker generated inside the throwaway local container for this proof.
Impact
On a deployment using SQLChatAgent against PostgreSQL with a role able to…
- Record
PYSEC-2026-2577- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
langroidPyPI |
through 0.65.0 | 0.65.1 |
langroidPyPI |
before 0.65.1, plus listed versions 0.1.1000.1.1010.1.1020.1.1030.1.104 Show 45 moreShow less0.1.1050.1.1060.1.1070.1.1080.1.1090.1.110.1.1100.1.1110.1.1120.1.1130.1.1140.1.1170.1.1180.1.1190.1.120.1.1200.1.1210.1.1220.1.1230.1.1240.1.1250.1.1260.1.1270.1.1280.1.1290.1.130.1.1300.1.1310.1.1320.1.1330.1.1340.1.1350.1.1360.1.1370.1.1380.1.1390.1.1400.1.1410.1.1420.1.1430.1.1440.1.1450.1.1470.1.1480.1.149 |
0.65.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-54760 is a critical vulnerability (CVSS 9.3) in Langroid, published July 6, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.65%, the 51st percentile. Fixed in langroid 0.65.1.
References
Left out here: 483 versions and the rest of 3 source descriptions. The JSON record has them.