PraisonAI's AI agent conversation persistence layer contains SQL injection across nine database backends — MySQL, PostgreSQL, async variants, Turso, SingleStore, Supabase, and SurrealDB — through an unvalidated `table_prefix` parameter inserted directly into raw SQL strings, totaling 52 injection points. The prior fix for CVE-2026-40315 patched only the SQLite backend, leaving every other backend exposed; any multi-tenant deployment where `table_prefix` derives from tenant identifiers, API parameters, or user-editable configuration is exploitable by low-privileged network attackers (CVSS 8.1, no KEV or public exploit currently). With 11 downstream dependents and 45 other CVEs in the same package signaling a pattern of inadequate security hardening, the blast radius includes arbitrary database read, write, and delete against full agent conversation histories — and on PostgreSQL, a second injection vector through the unvalidated `schema` parameter enables full schema destruction. Upgrade immediately to praisonaiagents 1.6.8 or praisonai 4.5.149; if patching is not immediately possible, enforce alphanumeric-plus-underscore validation on `table_prefix` at all backend instantiation points and audit database logs for anomalous DDL patterns.
What is the risk?
High risk for multi-tenant AI agent deployments. CVSS 8.1 with a network-accessible attack vector, low privilege requirement, and no user interaction needed. Default single-tenant deployments using the hardcoded 'praison_' prefix are unaffected unless external input can reach the parameter. The incomplete patch — 9 of 10 backends missed — and 52 total injection points make this a systemic rather than isolated flaw, suggesting the original patch was not reviewed across the full backend surface. PostgreSQL's additional schema injection vector amplifies impact for organizations using Postgres or Supabase backends. No public exploit or KEV listing currently, but the PoC is trivial and requires only basic SQL injection knowledge.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| PraisonAI | pip | <= 4.5.148 | 4.5.149 |
| PraisonAI Agents | pip | <= 1.6.7 | 1.6.8 |
How severe is it?
What is the attack surface?
What should I do?
7 steps-
Upgrade praisonaiagents to 1.6.8+ or praisonai to 4.5.149+ immediately.
-
If patching is delayed, add input validation in all 9 affected backends:
if not re.match(r'^[a-zA-Z0-9_]*$', table_prefix): raise ValueError(...). -
For PostgreSQL backends, apply identical validation to the
schemaparameter. -
Audit deployments to determine whether
table_prefixis derived from external input (tenant IDs, API request parameters, user-editable config). -
Review database audit logs for anomalous DDL operations (CREATE TABLE with unexpected names, DROP TABLE, CREATE SCHEMA, DROP SCHEMA).
-
For multi-tenant architectures, enforce an allowlist-based prefix system tied to internal tenant UUIDs that never include external string input.
-
Also validate
table_nameinpraisonai-agents/praisonaiagents/storage/backends.py:179(SQLiteBackend) which is separately affected.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is GHSA-rg3h-x3jw-7jm5?
PraisonAI's AI agent conversation persistence layer contains SQL injection across nine database backends — MySQL, PostgreSQL, async variants, Turso, SingleStore, Supabase, and SurrealDB — through an unvalidated `table_prefix` parameter inserted directly into raw SQL strings, totaling 52 injection points. The prior fix for CVE-2026-40315 patched only the SQLite backend, leaving every other backend exposed; any multi-tenant deployment where `table_prefix` derives from tenant identifiers, API parameters, or user-editable configuration is exploitable by low-privileged network attackers (CVSS 8.1, no KEV or public exploit currently). With 11 downstream dependents and 45 other CVEs in the same package signaling a pattern of inadequate security hardening, the blast radius includes arbitrary database read, write, and delete against full agent conversation histories — and on PostgreSQL, a second injection vector through the unvalidated `schema` parameter enables full schema destruction. Upgrade immediately to praisonaiagents 1.6.8 or praisonai 4.5.149; if patching is not immediately possible, enforce alphanumeric-plus-underscore validation on `table_prefix` at all backend instantiation points and audit database logs for anomalous DDL patterns.
Is GHSA-rg3h-x3jw-7jm5 actively exploited?
No confirmed active exploitation of GHSA-rg3h-x3jw-7jm5 has been reported, but organizations should still patch proactively.
How to fix GHSA-rg3h-x3jw-7jm5?
1. Upgrade praisonaiagents to 1.6.8+ or praisonai to 4.5.149+ immediately. 2. If patching is delayed, add input validation in all 9 affected backends: `if not re.match(r'^[a-zA-Z0-9_]*$', table_prefix): raise ValueError(...)`. 3. For PostgreSQL backends, apply identical validation to the `schema` parameter. 4. Audit deployments to determine whether `table_prefix` is derived from external input (tenant IDs, API request parameters, user-editable config). 5. Review database audit logs for anomalous DDL operations (CREATE TABLE with unexpected names, DROP TABLE, CREATE SCHEMA, DROP SCHEMA). 6. For multi-tenant architectures, enforce an allowlist-based prefix system tied to internal tenant UUIDs that never include external string input. 7. Also validate `table_name` in `praisonai-agents/praisonaiagents/storage/backends.py:179` (SQLiteBackend) which is separately affected.
What systems are affected by GHSA-rg3h-x3jw-7jm5?
This vulnerability affects the following AI/ML architecture patterns: agent frameworks, multi-tenant AI agent deployments, conversational AI systems, AI agent memory and persistence layers.
What is the CVSS score for GHSA-rg3h-x3jw-7jm5?
GHSA-rg3h-x3jw-7jm5 has a CVSS v3.1 base score of 8.1 (HIGH).
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0010.001 AI Software AML.T0025 Exfiltration via Cyber Means AML.T0049 Exploit Public-Facing Application AML.T0085 Data from AI Services Compliance Controls Affected
What are the technical details?
Original Advisory
The fix for [CVE-2026-40315](https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-x783-xp3g-mqhp) added input validation to `SQLiteConversationStore` only. Nine sibling backends — MySQL, PostgreSQL, async SQLite/MySQL/PostgreSQL, Turso, SingleStore, Supabase, SurrealDB — pass `table_prefix` straight into f-string SQL. Same root cause, same code pattern, same exploitation. 52 unvalidated injection points across the codebase. `postgres.py` additionally accepts an unvalidated `schema` parameter used directly in DDL. ### Severity **High** — CWE-89 (SQL Injection) CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N — **8.1** Exploitable in any deployment where `table_prefix` is derived from external input (multi-tenant setups, API-driven configuration, user-modifiable config files). Default config (`"praison_"`) is not affected. ### Details The [CVE-2026-40315 fix](https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-x783-xp3g-mqhp) added this guard to `sqlite.py:52`: ```python # sqlite.py — PATCHED import re if not re.match(r'^[a-zA-Z0-9_]*$', table_prefix): raise ValueError("table_prefix must contain only alphanumeric characters and underscores") ``` The following backends perform the identical `table_prefix → f-string SQL` pattern **without this guard**: | Backend | File | Line | Injection points | | ---------------- | -------------------------------------------- | --------------- | ----------------------- | | MySQL | `persistence/conversation/mysql.py` | 65 | 5 | | PostgreSQL | `persistence/conversation/postgres.py` | 89 (+schema:88) | 10 | | Async SQLite | `persistence/conversation/async_sqlite.py` | 43 | 13 | | Async MySQL | `persistence/conversation/async_mysql.py` | 65 | 13 | | Async PostgreSQL | `persistence/conversation/async_postgres.py` | 63 | 13 | | Turso/LibSQL | `persistence/conversation/turso.py` | 66 | 9 | | SingleStore | `persistence/conversation/singlestore.py` | 51 | 7 | | Supabase | `persistence/conversation/supabase.py` | 68 | 9 | | SurrealDB | `persistence/conversation/surrealdb.py` | 57 | 8 | | **Total** | **9 backends** | | **52 injection points** | Additionally, `praisonai-agents/praisonaiagents/storage/backends.py:179` (`SQLiteBackend`) accepts `table_name` without validation. ### PoC ```python #!/usr/bin/env python3 """ Demonstrates: sqlite.py rejects malicious table_prefix, mysql.py accepts it. Run: python3 poc.py (no dependencies required) """ import re payload = "x'; DROP TABLE users; --" # ── SQLite (patched) ──────────────────────────────────────────────── try: if not re.match(r'^[a-zA-Z0-9_]*$', payload): raise ValueError("blocked") print(f"[SQLite] FAIL — accepted: {payload}") except ValueError: print(f"[SQLite] OK — rejected malicious table_prefix") # ── MySQL (unpatched) ─────────────────────────────────────────────── sessions_table = f"{payload}sessions" sql = f"CREATE TABLE IF NOT EXISTS {sessions_table} (session_id VARCHAR(255) PRIMARY KEY)" print(f"[MySQL] VULN — generated SQL:\n {sql}") # ── PostgreSQL (unpatched — both table_prefix AND schema) ────────── schema = "public; DROP SCHEMA data CASCADE; --" sessions_table = f"{schema}.praison_sessions" sql = f"CREATE SCHEMA IF NOT EXISTS {schema}" print(f"[Postgres] VULN — schema injection:\n {sql}") ``` Output: ``` [SQLite] OK — rejected malicious table_prefix [MySQL] VULN — generated SQL: CREATE TABLE IF NOT EXISTS x'; DROP TABLE users; --sessions (session_id VARCHAR(255) PRIMARY KEY) [Postgres] VULN — schema injection: CREATE SCHEMA IF NOT EXISTS public; DROP SCHEMA data CASCADE; -- ``` ### Vulnerable code (mysql.py, representative) ```python # mysql.py:65-67 — NO validation self.table_prefix = table_prefix # ← raw input self.sessions_table = f"{table_prefix}sessions" # ← into identifier self.messages_table = f"{table_prefix}messages" # mysql.py:105 — straight into DDL cur.execute(f""" CREATE TABLE IF NOT EXISTS {self.sessions_table} ( session_id VARCHAR(255) PRIMARY KEY, ... ) """) ``` Compare with the patched `sqlite.py:52`: ```python # sqlite.py:52-53 — HAS validation if not re.match(r'^[a-zA-Z0-9_]*$', table_prefix): raise ValueError("table_prefix must contain only alphanumeric characters and underscores") ``` ### Impact When `table_prefix` originates from untrusted input — multi-tenant tenant names, API request parameters, user-editable config — an attacker achieves **arbitrary SQL execution** against the backing database. The injected SQL runs in the context of DDL and DML operations (CREATE TABLE, INSERT, SELECT, DELETE), giving the attacker read/write/delete access to the entire database. PostgreSQL's `schema` parameter adds a second injection vector in DDL (`CREATE SCHEMA IF NOT EXISTS {schema}`).
Exploitation Scenario
A threat actor targets a multi-tenant SaaS platform running PraisonAI agents where conversation data is stored in tables prefixed by tenant identifier. During account registration, the attacker submits a malicious tenant name such as `x'; INSERT INTO praison_sessions SELECT * FROM praison_sessions WHERE '1'='1'; --`. When PraisonAI initializes the MySQL backend, the prefix is interpolated unescaped into a CREATE TABLE DDL, executing the injected SELECT and exfiltrating all session data from other tenants. For a destructive attack, a payload of `x'; DROP TABLE praison_messages; --` wipes all agent conversation history. Against PostgreSQL, a schema-level payload like `public; DROP SCHEMA production CASCADE; --` passed as the `schema` parameter destroys the entire production schema in a single DDL execution, achieving full database destruction with no further escalation required.
Weaknesses (CWE)
CWE-89 — Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection'): The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data.
- [Architecture and Design] Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid [REF-1482]. For example, consider using persistence layers such as Hibernate or Enterprise Java Beans, which can provide significant protection against SQL injection if used properly.
- [Architecture and Design] If available, use structured mechanisms that automatically enforce the separation between data and code. These mechanisms may be able to provide the relevant quoting, encoding, and validation automatically, instead of relying on the developer to provide this capability at every point where output is generated. Process SQL queries using prepared statements, parameterized queries, or stored procedures. These features should accept parameters or variables and support strong typing. Do not dynamically construct and execute query strings within these features using "exec" or similar functionality, since this may re-introduce the possibility of SQL injection. [REF-867]
Source: MITRE CWE corpus.
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N References
Timeline
Related Vulnerabilities
CVE-2026-34938 10.0 praisonaiagents: sandbox bypass enables full host RCE
Same package: praisonaiagents CVE-2026-39888 10.0 praisonaiagents: sandbox escape enables host RCE
Same package: praisonaiagents CVE-2026-47392 9.9 praisonaiagents: RCE via Python sandbox bypass
Same package: praisonaiagents GHSA-vc46-vw85-3wvm 9.8 PraisonAI: RCE via malicious workflow YAML execution
Same package: praisonaiagents CVE-2026-47391 9.8 PraisonAI: Unauth RCE via A2A eval injection
Same package: praisonaiagents