#670·QAnything

unauthenticated cross-user file/document disclosure (/get_file_base64, /get_doc)

Author: geo-chenCreated Jul 13, 2026Updated Jul 13, 2026

是否已有关于该错误的issue或讨论? | Is there an existing issue / discussion for this?

  • 我已经搜索过已有的issues和讨论 | I have searched the existing issues / discussions

该问题是否在FAQ中有解答? | Is there an existing answer for this in FAQ?

  • 我已经搜索过FAQ | I have searched FAQ

当前行为 | Current Behavior

reported via email on 9 June 2026 - no response:

I found a security issue in QAnything (confirmed on current main, commit 65de1042) and reproduced it against a running stack (MySQL + Milvus + Elasticsearch).

Summary

Two unauthenticated POST endpoints return full content by server-assigned ID with no ownership check:

  • /api/local_doc_qa/get_file_base64 returns the base64 of any uploaded file given file_id.
  • /api/local_doc_qa/get_doc returns any parsed document chunk given doc_id.

Neither requires authentication (routes have no auth middleware; handlers carry only @get_time_async), and the backing SQL has no user_id predicate (SELECT file_location FROM File WHERE file_id=%s; SELECT json_data FROM Documents WHERE doc_id=%s). The wider API treats user_id as a self-asserted string (list_files takes a caller-supplied user_id, user_info defaults to "1234"), so it is not a real boundary. The unauthenticated get_user_id (kb_id -> user_id) and list_files endpoints supply the IDs needed.

Where

qanything_kernel/qanything_server/handler.py:1452 (get_file_base64), :1192 (get_doc) qanything_kernel/connector/database/mysql/mysql_client.py:880 (get_file_location), :620 (get_document_by_doc_id) qanything_kernel/qanything_server/sanic_api.py (routes registered, no auth)

Proof of concept (no Authorization header, non-owner)

POST /api/local_doc_qa/get_file_base64 {"file_id":"Fabc...cde"} -> file_base64 decodes to the victim's file content. POST /api/local_doc_qa/get_doc {"doc_id":"Fabc...cde_1"} -> the victim's chunk text (incl. an embedded secret token).

Impact

Unauthenticated, cross-tenant disclosure of uploaded files and extracted text (the core asset of a private knowledge-base product), with companion unauth endpoints providing the IDs.

Suggested fix

Require real authentication (verified session/token, not a self-asserted user_id); in get_file_base64/get_doc resolve the owner of the requested id and enforce it matches the caller (add the user_id predicate to the SQL); apply the same to get_user_id/list_files and the other read endpoints.

期望行为 | Expected Behavior

No response

运行环境 | Environment

markdown

QAnything日志 | QAnything logs

No response

复现方法 | Steps To Reproduce

No response

备注 | Anything else?

No response

Source: netease-youdao/QAnything