id: PYSEC-2026-2577 published: "2026-07-13T15:46:28.525610Z" modified: "2026-07-13T16:04:33.415429Z" aliases: - CVE-2026-54760 - GHSA-6xc5-4r68-67fc summary: "Langroid: SQLChatAgent dangerous-function blocklist can be bypassed with quoted or schema-qualified pg_read_file calls" details: "# SQLChatAgent `_validate_query` dangerous-pattern regex is bypassable via quoted/commented/qualified function names\n\n## Summary\n\nThe `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*\\(`.\n\nPostgreSQL 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.\n\n## Affected Code\n\nTested against current `main` commit:\n\n`6e8e7b2bb23ec04c1c25be479f16b8cc9a4f8796`\n\nThe current source still contains:\n\n```python\nre.compile(r\"\\bpg_(read|stat|ls|current_logfile)[A-Za-z0-9_]*\\s*\\(\", re.IGNORECASE)\n```\n\n`_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.\n\n## Root Cause\n\nThe 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.\n\n## Auth Boundary\n\nThe 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`.\n\nThis is not a new unauthenticated endpoint or product-wide SQL injection; it applies when untrusted user content can influence SQLChatAgent's generated SQL.\n\n## Reproduction\n\nThe 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.\n\nTranscript excerpt:\n\n```text\nCONTROL \"SELECT pg_read_file('/etc/passwd')\" -> REJECTED: matches '\\\\bpg_(read|stat|ls|current_logfile)[A-Za-z0-9_]*\\\\s*\\\\('\nBYPASS 'SELECT \"pg_read_file\"(\\'/etc/passwd\\')' -> ALLOWED (validator returned None -> would execute)\nBYPASS \"SELECT pg_read_file/**/('/etc/passwd')\" -> ALLOWED (validator returned None -> would execute)\nBYPASS 'SELECT pg_catalog.\"pg_read_file\"(\\'/etc/passwd\\')' -> ALLOWED (validator returned None -> would execute)\n\n=== Part B: real PostgreSQL execution of the bypass ===\nconnected; is_superuser=t\n executed bypass 'SELECT \"pg_read_file\"(\\'\\')' -> file contents returned: 'LANGROID_SAFE_MARKER_...'\n executed bypass \"SELECT pg_read_file/**/('')\" -> file contents returned: 'LANGROID_SAFE_MARKER_...'\n executed bypass 'SELECT pg_catalog.\"pg_read_file\"(\\'\\')' -> file contents returned: 'LANGROID_SAFE_MARKER_...'\n\nRESULT: VULNERABLE\n```\n\nThe 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.\n\n## Impact\n\nOn a deployment using `SQLChatAgent` against PostgreSQL with a role able to call `pg_read_file` (superuser, or a role granted `pg_read_server_files`), an attacker who can influence LLM-generated SQL can coerce the agent into emitting one of the obfuscated queries and read files accessible to the PostgreSQL server process through `pg_read_file`.\n\nThis is the same impact and precondition shape as the published `pg_read_file` advisory, but it targets the bypassability of the current regex-based fix rather than the pre-fix absence of a `pg_read_file` block.\n\nSeverity: High by parity with the published parent advisory; not Critical. CWE-184 leading to server-side file read.\n\n## Suggested Fix\n\nDo not rely on raw-text regex matching for dangerous-call detection. After the existing `sqlglot` parse, walk the AST and reject any function invocation whose normalized, unquoted, schema-stripped, case-folded name is in a dangerous set such as `pg_read_file`, `pg_read_binary_file`, `pg_ls_dir`, `pg_stat_file`, `lo_import`, `lo_export`, `load_file`, or `load_extension`.\n\nAlso recommend running SQLChatAgent with a least-privilege database role that lacks `pg_read_server_files`." affected: - package: name: langroid ecosystem: PyPI purl: pkg:pypi/langroid ranges: - type: ECOSYSTEM events: - introduced: "0" - fixed: 0.65.1 versions: - 0.1.100 - 0.1.101 - 0.1.102 - 0.1.103 - 0.1.104 - 0.1.105 - 0.1.106 - 0.1.107 - 0.1.108 - 0.1.109 - 0.1.11 - 0.1.110 - 0.1.111 - 0.1.112 - 0.1.113 - 0.1.114 - 0.1.117 - 0.1.118 - 0.1.119 - 0.1.12 - 0.1.120 - 0.1.121 - 0.1.122 - 0.1.123 - 0.1.124 - 0.1.125 - 0.1.126 - 0.1.127 - 0.1.128 - 0.1.129 - 0.1.13 - 0.1.130 - 0.1.131 - 0.1.132 - 0.1.133 - 0.1.134 - 0.1.135 - 0.1.136 - 0.1.137 - 0.1.138 - 0.1.139 - 0.1.140 - 0.1.141 - 0.1.142 - 0.1.143 - 0.1.144 - 0.1.145 - 0.1.147 - 0.1.148 - 0.1.149 - 0.1.15 - 0.1.150 - 0.1.151 - 0.1.152 - 0.1.153 - 0.1.154 - 0.1.155 - 0.1.156 - 0.1.157 - 0.1.158 - 0.1.159 - 0.1.160 - 0.1.161 - 0.1.162 - 0.1.163 - 0.1.164 - 0.1.165 - 0.1.166 - 0.1.167 - 0.1.168 - 0.1.169 - 0.1.17 - 0.1.170 - 0.1.171 - 0.1.172 - 0.1.173 - 0.1.174 - 0.1.175 - 0.1.176 - 0.1.177 - 0.1.178 - 0.1.179 - 0.1.18 - 0.1.181 - 0.1.182 - 0.1.183 - 0.1.184 - 0.1.185 - 0.1.186 - 0.1.187 - 0.1.188 - 0.1.189 - 0.1.19 - 0.1.190 - 0.1.191 - 0.1.192 - 0.1.193 - 0.1.194 - 0.1.195 - 0.1.196 - 0.1.197 - 0.1.198 - 0.1.199 - 0.1.20 - 0.1.200 - 0.1.201 - 0.1.202 - 0.1.203 - 0.1.205 - 0.1.206 - 0.1.207 - 0.1.208 - 0.1.209 - 0.1.21 - 0.1.210 - 0.1.211 - 0.1.212 - 0.1.213 - 0.1.214 - 0.1.215 - 0.1.217 - 0.1.218 - 0.1.219 - 0.1.22 - 0.1.221 - 0.1.222 - 0.1.224 - 0.1.225 - 0.1.226 - 0.1.227 - 0.1.228 - 0.1.229 - 0.1.23 - 0.1.230 - 0.1.231 - 0.1.233 - 0.1.234 - 0.1.235 - 0.1.236 - 0.1.237 - 0.1.238 - 0.1.239 - 0.1.24 - 0.1.240 - 0.1.241 - 0.1.243 - 0.1.244 - 0.1.245 - 0.1.246 - 0.1.247 - 0.1.248 - 0.1.249 - 0.1.25 - 0.1.250 - 0.1.251 - 0.1.252 - 0.1.253 - 0.1.254 - 0.1.256 - 0.1.257 - 0.1.258 - 0.1.26 - 0.1.260 - 0.1.261 - 0.1.262 - 0.1.263 - 0.1.265 - 0.1.27 - 0.1.28 - 0.1.29 - 0.1.30 - 0.1.31 - 0.1.32 - 0.1.33 - 0.1.34 - 0.1.35 - 0.1.36 - 0.1.37 - 0.1.38 - 0.1.39 - 0.1.40 - 0.1.41 - 0.1.42 - 0.1.43 - 0.1.44 - 0.1.46 - 0.1.47 - 0.1.48 - 0.1.49 - 0.1.50 - 0.1.51 - 0.1.52 - 0.1.53 - 0.1.54 - 0.1.55 - 0.1.56 - 0.1.57 - 0.1.58 - 0.1.59 - 0.1.60 - 0.1.61 - 0.1.62 - 0.1.63 - 0.1.64 - 0.1.65 - 0.1.66 - 0.1.67 - 0.1.68 - 0.1.69 - 0.1.72 - 0.1.73 - 0.1.76 - 0.1.77 - 0.1.78 - 0.1.79 - 0.1.8 - 0.1.80 - 0.1.81 - 0.1.83 - 0.1.84 - 0.1.85 - 0.1.86 - 0.1.87 - 0.1.88 - 0.1.89 - 0.1.9 - 0.1.90 - 0.1.91 - 0.1.92 - 0.1.93 - 0.1.94 - 0.1.95 - 0.1.96 - 0.1.97 - 0.1.98 - 0.1.99 - 0.10.0 - 0.10.1 - 0.10.2 - 0.11.0 - 0.12.0 - 0.13.0 - 0.14.0 - 0.15.0 - 0.15.1 - 0.15.2 - 0.16.0 - 0.16.1 - 0.16.2 - 0.16.3 - 0.16.4 - 0.16.5 - 0.16.6 - 0.16.7 - 0.17.0 - 0.17.1 - 0.18.0 - 0.18.1 - 0.18.2 - 0.18.3 - 0.19.0 - 0.19.1 - 0.19.2 - 0.19.3 - 0.19.4 - 0.19.5 - 0.2.0 - 0.2.10 - 0.2.11 - 0.2.12 - 0.2.2 - 0.2.3 - 0.2.4 - 0.2.5 - 0.2.6 - 0.2.7 - 0.2.9 - 0.20.0 - 0.20.1 - 0.21.0 - 0.22.0 - 0.22.1 - 0.22.2 - 0.22.3 - 0.22.4 - 0.22.5 - 0.22.6 - 0.22.7 - 0.23.0 - 0.23.1 - 0.23.2 - 0.23.3 - 0.24.1 - 0.25.0 - 0.26.0 - 0.26.1 - 0.26.2 - 0.27.1 - 0.27.2 - 0.27.3 - 0.27.4 - 0.28.0 - 0.28.1 - 0.28.2 - 0.28.3 - 0.28.4 - 0.28.5 - 0.28.6 - 0.28.7 - 0.29.0 - 0.3.0 - 0.3.1 - 0.30.0 - 0.30.1 - 0.31.0 - 0.31.1 - 0.31.2 - 0.31.3 - 0.32.0 - 0.32.1 - 0.32.2 - 0.33.10 - 0.33.11 - 0.33.12 - 0.33.13 - 0.33.3 - 0.33.4 - 0.33.6 - 0.33.7 - 0.33.8 - 0.33.9 - 0.34.0 - 0.34.1 - 0.35.0 - 0.35.1 - 0.36.0 - 0.36.1 - 0.37.0 - 0.37.1 - 0.37.2 - 0.37.3 - 0.37.4 - 0.37.5 - 0.37.6 - 0.37.7 - 0.38.0 - 0.39.0 - 0.39.1 - 0.39.2 - 0.39.3 - 0.39.4 - 0.39.5 - 0.40.0 - 0.41.0 - 0.41.1 - 0.41.2 - 0.41.3 - 0.41.4 - 0.41.5 - 0.42.0 - 0.42.1 - 0.42.10 - 0.42.2 - 0.42.3 - 0.42.4 - 0.42.5 - 0.42.6 - 0.42.7 - 0.42.8 - 0.42.9 - 0.43.0 - 0.43.1 - 0.44.0 - 0.45.0 - 0.45.1 - 0.45.10 - 0.45.2 - 0.45.3 - 0.45.4 - 0.45.5 - 0.45.6 - 0.45.7 - 0.45.8 - 0.46.0 - 0.47.0 - 0.47.1 - 0.47.2 - 0.48.0 - 0.48.1 - 0.48.2 - 0.48.3 - 0.49.0 - 0.49.1 - 0.5.0 - 0.5.1 - 0.50.0 - 0.50.1 - 0.50.10 - 0.50.11 - 0.50.12 - 0.50.2 - 0.50.3 - 0.50.4 - 0.50.5 - 0.50.6 - 0.50.7 - 0.50.8 - 0.50.9 - 0.51.0 - 0.51.1 - 0.51.2 - 0.52.0 - 0.52.1 - 0.52.2 - 0.52.3 - 0.52.4 - 0.52.5 - 0.52.6 - 0.52.7 - 0.52.8 - 0.52.9 - 0.53.0 - 0.53.1 - 0.53.10 - 0.53.11 - 0.53.12 - 0.53.13 - 0.53.14 - 0.53.15 - 0.53.16 - 0.53.2 - 0.53.4 - 0.53.5 - 0.53.6 - 0.53.7 - 0.53.8 - 0.54.0 - 0.54.1 - 0.54.2 - 0.55.0 - 0.55.1 - 0.56.0 - 0.56.1 - 0.56.10 - 0.56.11 - 0.56.12 - 0.56.13 - 0.56.14 - 0.56.15 - 0.56.16 - 0.56.17 - 0.56.18 - 0.56.19 - 0.56.2 - 0.56.3 - 0.56.4 - 0.56.5 - 0.56.6 - 0.56.7 - 0.56.8 - 0.56.9 - 0.57.0 - 0.58.0 - 0.58.1 - 0.58.2 - 0.58.3 - 0.59.0 - 0.59.0b1 - 0.59.0b2 - 0.59.0b3 - 0.59.1 - 0.59.10 - 0.59.11 - 0.59.12 - 0.59.13 - 0.59.14 - 0.59.15 - 0.59.16 - 0.59.17 - 0.59.18 - 0.59.19 - 0.59.2 - 0.59.20 - 0.59.21 - 0.59.22 - 0.59.23 - 0.59.24 - 0.59.25 - 0.59.26 - 0.59.27 - 0.59.28 - 0.59.29 - 0.59.3 - 0.59.30 - 0.59.31 - 0.59.32 - 0.59.33 - 0.59.34 - 0.59.35 - 0.59.36 - 0.59.37 - 0.59.38 - 0.59.39 - 0.59.4 - 0.59.5 - 0.59.6 - 0.59.7 - 0.59.8 - 0.59.9 - 0.6.0 - 0.6.1 - 0.6.3 - 0.6.4 - 0.6.5 - 0.6.6 - 0.6.7 - 0.60.0 - 0.60.1 - 0.60.2 - 0.60.3 - 0.61.0 - 0.61.1 - 0.62.0 - 0.63.0 - 0.64.0 - 0.65.0 - 0.8.0 - 0.9.0 - 0.9.1 - 0.9.2 - 0.9.3 - 0.9.4 - 0.9.5 references: - type: WEB url: https://github.com/langroid/langroid/security/advisories/GHSA-6xc5-4r68-67fc - type: PACKAGE url: https://github.com/langroid/langroid - type: PACKAGE url: https://pypi.org/project/langroid - type: ADVISORY url: https://github.com/advisories/GHSA-6xc5-4r68-67fc - type: ADVISORY url: https://nvd.nist.gov/vuln/detail/CVE-2026-54760 severity: - type: CVSS_V4 score: 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