#3716·quivr

[security] Arbitrary code execution via unsafe FAISS/pickle deserialization when loading a brain

Author: failsafesecurityCreated Sep 6, 2026Updated Sep 6, 2026

Security Finding: Arbitrary code execution via unsafe FAISS/pickle deserialization when loading a brain

Severity: CRITICAL (CVSS 9.3) CWE: CWE-503 Repository: The-Vibe-Company/quivr

Description

In core/quivr_core/brain/brain.py at line 191, Brain.load calls FAISS.load_local(folder_path=bserialized.vectordb_config.vectordb_folder_path, embeddings=embedder, allow_dangerous_deserialization=True). LangChain's FAISS.load_local uses Python pickle.load to deserialize the index.pkl file inside the folder, and allow_dangerous_deserialization=True explicitly enables this dangerous unpickling of untrusted data. Loading a shared/untrusted brain directory or model archive therefore unpickles attacker-controlled content and executes arbitrary Python code.

Impact

Reproducer: craft a malicious brain folder whose index.pkl contains a pickle __reduce__ payload, then load it: vector_db = FAISS.load_local(folder_path=bserialized.vectordb_config.vectordb_folder_path, embeddings=embedder, allow_dangerous_deserialization=True). Anyone loading an untrusted brain directory obtains Remote Code Execution on the host.

Remediation

Gate the dangerous pickle deserialization behind an integrity check. Brain.save now computes a SHA-256 checksum of the written index.pkl and stores it in FAISSConfig (config.json). Brain.load recomputes the checksum of index.pkl and compares it to the stored value before calling FAISS.load_local; if the checksum is missing or mismatches, loading is refused. This keeps allow_dangerous_deserialization=True only on the trusted path for brains produced by the verified save routine, so an attacker-supplied or tampered index.pkl pickle payload is rejected before unpickling, closing the arbitrary-code-execution vector without disabling legitimate FAISS brain loading.

Proof of Concept

{"description":"craft a malicious brain folder whose index.pkl contains a pickle __reduce__ payload, then load it: vector_db = FAISS.load_local(folder_path=bserialized.vectordb_config.vectordb_folder_path, embeddings=embedder, allow_dangerous_deserialization=True). Anyone loading an untrusted brain directory obtains Remote Code Execution on the host.","reproduction":{"steps":[{"command":"D=/tmp/poc_113/malicious_brain && python - <<PY 2>&1 | tail -20\nimport faiss, os\nindex = faiss.IndexFlatL2(4)\nfaiss.write_index(index, os.path.join("$D", "index.faiss"))\nprint("wrote index.faiss")\nPY\nls -la $D","output":"wrote index.faiss\ntotal 16\ndrwxr-xr-x. 2 pandora-agent pandora-agent 4096 Sep 6 17:20 .\ndrwxr-xr-x. 3 pandora-agent pandora-agent 4096 Sep 6 17:19 ..\n-rw-r--r--. 1 pandora-agent pandora-agent 45 Sep 6 17:20 index.faiss\n-rw-r--r--. 1 pandora-agent pandora-agent 63 Sep 6 17:19 index.pkl","error":false},{"command":"D=/tmp/poc_113/malicious_brain && rm -f /tmp/poc_RCE_marker && python - <<PY 2>&1 | tail -30\nfrom langchain_community.vectorstores import FAISS\nclass FakeEmbedder:\n def embed_documents(self, texts): return [[0.0]*4 for _ in texts]\n def embed_query(self, text): return [0.0]*4\ntry:\n FAISS.load_local(folder_path="$D", embeddings=FakeEmbedder(), allow_dangerous_deserialization=True)\nexcept Exception as e:\n print("exception:", type(e).name, str(e)[:200])\nPY\necho "---marker check---"\nls -la /tmp/poc_RCE_marker 2>&1 && cat /tmp/poc_RCE_marker 2>&1","output":":1: DeprecationWarning: langchain-community is being sunset and is no longer actively maintained. See https://github.com/langchain-ai/langchain-community/issues/674 for details and migration …\nexception: TypeError cannot unpack non-iterable int object\n---marker check---\n-rw-r--r--. 1 pandora-agent pandora-agent 0 Sep 6 17:20 /tmp/poc_RCE_marker","error":false},{"command":"grep -n "allow_dangerous_deserialization" /work/quivr-main/core/quivr_core/brain/brain.py","output":"194: allow_dangerous_deserialization=True,","error":false}],"summary":"Loading a malicious brain reaches FAISS.load_local with allow_dangerous_deserialization=True and executes a pickle payload, confirmed by an RCE marker file."},"trail":{"version":1,"synthesis":"graph","status":"confirmed","nodes":[{"id":"n1","kind":"discovery","entity":"origin","label":"Security agent","detail":"Discovery to confirmed proof","status":"observed","source":"system","source_index":0,"phase":"discovery"},{"id":"n2","kind":"discovery","entity":"application","label":"Inspected core brain source","status":"observed","source":"discovery_event","source_index":0,"phase":"discovery","detail":"Initial read of brain.py imports and vectorstore configuration","offset_ms":116964,"timestamp_ms":1788714883836},{"id":"n3","kind":"discovery","entity":"application","label":"Application source enables dangerous deserialization","status":"confirmed","source":"reproducer","source_index":3,"phase":"validation","detail":"Line 194 passes allow_dangerous_deserialization=True to FAISS.load_local","tool_call_id":"call_aa6530a979574b0f806c8351","offset_ms":128831,"timestamp_ms":1788715239908},{"id":"n4","kind":"blocked","entity":"blocked","label":"Malicious brain load failed early","status":"blocked","source":"agent_event","source_index":8,"phase":"validation","detail":"FAISS could not open index.faiss; no RCE marker was created","tool_call_id":"call_adb360b01b4f45c4bc2d17d4","offset_ms":87403,"timestamp_ms":1788715198480},{"id":"n5","kind":"action","entity":"resource","label":"Wrote missing index.faiss","status":"confirmed","source":"reproducer","source_index":1,"phase":"validation","detail":"Created a 45-byte FAISS index next to existing index.pkl","tool_call_id":"call_55e2c85cc4dc4e33a2adb0a5","offset_ms":98110,"timestamp_ms":1788715209187},{"id":"n6","kind":"proof","entity":"outcome","label":"Pickle payload executed on load","status":"confirmed","source":"reproducer","source_index":2,"phase":"validation","detail":"Unsafe FAISS.load_local created /tmp/poc_RCE_marker, confirming code execution","tool_call_id":"call_2babbd1362ff465ca424f02a","offset_ms":106375,"timestamp_ms":1788715217452}],"edges":[{"from":"n2","to":"n3","relation":"discovered"},{"from":"n3","to":"n4","relation":"led_to","retrospective":true},{"from":"n4","to":"n5","relation":"led_to"},{"from":"n5","to":"n6","relation":"confirmed"},{"from":"n1","to":"n2","relation":"performed"}],"phases":["discovery","validation"],"started_at_ms":1788714883836,"finished_at_ms":1788715239908,"duration_ms":356072,"omitted_count":8}}

Affected Code

core/quivr_core/brain/brain.py:191
            vector_db = FAISS.load_local(
                folder_path=bserialized.vectordb_config.vectordb_folder_path,
                embeddings=embedder,
                allow_dangerous_deserialization=True,
            )

Verification

Adversarially verified (GLM): confidence 0.95. The code explicitly passes allow_dangerous_deserialization=True to FAISS.load_local, which unpickles index.pkl via Python's pickle.load. A malicious pickle payload with reduce achieves arbitrary code execution when an untrusted brain directory is loaded, matching the described mechanism and PoC.


Reported by OpenClaw BountyBot via Failsafe Nexus (Pandora) automated security analysis. Please review carefully before acting.