VYPR
Medium severity6.3NVD Advisory· Published May 17, 2026· Updated May 18, 2026

CVE-2026-8754

CVE-2026-8754

Description

A vulnerability was detected in AstrBotDevs AstrBot up to 4.23.5. Impacted is the function post_file of the file astrbot/dashboard/routes/chat.py of the component File Upload Handler. The manipulation of the argument filename results in path traversal. It is possible to launch the attack remotely. The exploit is now public and may be used. Upgrading to version 4.23.6 is recommended to address this issue. The patch is identified as aaec41e5054569ceaa1113593a34da7568e2d211. You should upgrade the affected component.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A path traversal vulnerability in AstrBot's file upload handler allows authenticated remote attackers to write arbitrary files, potentially leading to RCE.

The vulnerability resides in the post_file function of the file upload handler in AstrBot's dashboard (file astrbot/dashboard/routes/chat.py). When processing file uploads, the application directly uses the user-supplied filename without sanitization, concatenating it with the configured attachments directory via os.path.join() [3]. This allows path traversal sequences (e.g., ../../) to escape the intended directory.

Exploitation requires authentication to the WebUI. An attacker can use default credentials (astrbot/astrbot) to obtain a JWT token, then send a crafted multipart request with a filename containing path traversal payloads. The PoC in [3] demonstrates writing a file to /tmp/pwned.txt by setting the filename to ../../../../../../../../tmp/pwned.txt. The server responds with a 200 OK and writes the file outside the intended directory.

This arbitrary file write can be leveraged to achieve remote code execution (e.g., overwriting Python scripts, configuration files, or injecting into startup scripts) and denial of service. The advisory [3] rates the impact as complete system compromise.

The vulnerability is addressed in version 4.23.6 with commit aaec41e5054569ceaa1113593a34da7568e2d211 [4]. The fix introduces a _sanitize_upload_filename() function that normalizes paths, rejects dangerous names, and ensures the final file path is relative to the attachments directory using pathlib [4]. Users are advised to upgrade to v4.23.6 or later [2].

AI Insight generated on May 18, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Patches

1
aaec41e50545

fix: prevent path traversal in file uploads (#7751)

https://github.com/AstrBotDevs/AstrBotbugkeepApr 24, 2026via nvd-ref
2 files changed · +51 4
  • astrbot/dashboard/routes/chat.py+19 4 modified
    @@ -5,6 +5,7 @@
     import uuid
     from contextlib import asynccontextmanager
     from copy import deepcopy
    +from pathlib import Path, PurePosixPath
     from typing import Any, cast
     
     from quart import Response as QuartResponse
    @@ -32,6 +33,16 @@
     SSE_HEARTBEAT = ": heartbeat\n\n"
     
     
    +def _sanitize_upload_filename(filename: str | None) -> str:
    +    if not filename:
    +        return f"{uuid.uuid4()!s}"
    +    normalized = filename.replace("\\", "/")
    +    name = PurePosixPath(normalized).name.replace("\x00", "").strip()
    +    if name in ("", ".", ".."):
    +        return f"{uuid.uuid4()!s}"
    +    return name
    +
    +
     @asynccontextmanager
     async def track_conversation(convs: dict, conv_id: str):
         convs[conv_id] = True
    @@ -333,7 +344,7 @@ async def post_file(self):
                 return Response().error("Missing key: file").__dict__
     
             file = post_data["file"]
    -        filename = file.filename or f"{uuid.uuid4()!s}"
    +        filename = _sanitize_upload_filename(file.filename)
             content_type = file.content_type or "application/octet-stream"
     
             # 根据 content_type 判断文件类型并添加扩展名
    @@ -346,12 +357,16 @@ async def post_file(self):
             else:
                 attach_type = "file"
     
    -        path = os.path.join(self.attachments_dir, filename)
    -        await file.save(path)
    +        attachments_dir = Path(self.attachments_dir).resolve(strict=False)
    +        file_path = (attachments_dir / filename).resolve(strict=False)
    +        if not file_path.is_relative_to(attachments_dir):
    +            return Response().error("Invalid filename").__dict__
    +
    +        await file.save(str(file_path))
     
             # 创建 attachment 记录
             attachment = await self.db.insert_attachment(
    -            path=path,
    +            path=str(file_path),
                 type=attach_type,
                 mime_type=content_type,
             )
    
  • tests/unit/test_upload_filename_sanitization.py+32 0 added
    @@ -0,0 +1,32 @@
    +"""Tests for upload filename sanitization."""
    +
    +from astrbot.dashboard.routes.chat import _sanitize_upload_filename
    +
    +
    +def test_sanitize_upload_filename_strips_posix_traversal():
    +    assert _sanitize_upload_filename("../../outside.txt") == "outside.txt"
    +
    +
    +def test_sanitize_upload_filename_strips_windows_traversal():
    +    assert _sanitize_upload_filename(r"..\\..\\outside.txt") == "outside.txt"
    +
    +
    +def test_sanitize_upload_filename_strips_fakepath():
    +    assert _sanitize_upload_filename(r"C:\\fakepath\\photo.png") == "photo.png"
    +
    +
    +def test_sanitize_upload_filename_falls_back_for_empty_values():
    +    generated = _sanitize_upload_filename("")
    +
    +    assert generated
    +    assert generated not in {".", ".."}
    +    assert "/" not in generated
    +    assert "\\" not in generated
    +
    +
    +def test_sanitize_upload_filename_removes_embedded_null_bytes():
    +    assert _sanitize_upload_filename("evil\x00.txt") == "evil.txt"
    +    assert _sanitize_upload_filename("\x00leading.txt") == "leading.txt"
    +    assert _sanitize_upload_filename("trailing\x00.txt\x00") == "trailing.txt"
    +    assert _sanitize_upload_filename("mid\x00dle.txt") == "middle.txt"
    +
    

Vulnerability mechanics

Synthesis attempt was rejected by the grounding validator. Re-run pending.

References

6

News mentions

0

No linked articles in our index yet.