Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-41496 — praisonai

🟠 CVSS 8.0 — High ⚠️ Exploit Public CWE-89 OSV
8.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

PraisonAI: SQL Injection via unvalidated table_prefix in 9 conversation store backends (incomplete fix for CVE-2026-40315)

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

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs low-level privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality high, integrity high, availability none.

CVSS metrics in full

The score comes from this vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: Low — the attack works reliably, with no preparation.
  • Privileges required: Low — an ordinary user account is enough.
  • User interaction: None — nobody has to be tricked into anything.
  • Scope: Unchanged — the damage stays inside the vulnerable component.
  • Confidentiality impact: High — total loss, or loss the attacker controls.
  • Integrity impact: High — total loss, or loss the attacker controls.
  • Availability impact: None.

Weakness class

CVE-2026-41496 is classified as CWE-89: SQL Injection. Untrusted input is concatenated into an SQL statement, letting an attacker change the query and reach data the request should not return.

Affected software

CVE-2026-41496 is recorded against 2 packages.

  • praisonai (fixed in 4.5.149)
  • praisonaiagents (fixed in 1.6.8)

Timeline and source

Published on 13 July 2026. A public exploit is known to exist, which raises the urgency of patching considerably. Record sourced from OSV.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Package)
pypi.org (Package)
github.com (Advisory)

Other advisories for this package

praisonai has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-89: SQL Injection) in other software:

Details

Severity HIGH
CVSS Score 8.0
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N
CWE CWE-89
Public Exploit ⚠️ Yes
Source OSV
Published 2026-07-13
Updated 2026-08-20
Modified 2026-07-13
Fix URL N/A

Affected Packages

Software From version Fixed in
praisonai 4.5.149
praisonaiagents 1.6.8

Similar Threats

Exploit Protection

Are you running praisonai?

CVE-2026-41496 carries CVSS 8.0 High rating and a public exploit already exists. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.

Check My Site For CVE-2026-41496 →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026