Skip to content

Arbitrary File Write via parseExcel Leading to Code Execution Through Alembic Import Processing

High
xuwei-fit2cloud published GHSA-wxv4-pw5w-wx79 Jun 9, 2026

Package

No package listed

Affected versions

<1.9.0

Patched versions

1.9.0

Description

Impact

The issue is not caused by a single vulnerability. Instead, multiple security weaknesses combine to create a reliable path from file upload to code execution.

An attacker can submit a crafted multipart upload request containing a controlled filename and attacker-controlled content. The application writes the supplied content to a filesystem location influenced by the attacker. During testing, this allowed placement of a Python module inside SQLBot's Alembic migration directory.

Although the upload request ultimately returns an error because the content is not a valid spreadsheet, the file is written to disk before parsing fails. The uploaded file therefore remains present on disk.

When SQLBot subsequently performs startup and migration processing, Alembic imports migration modules from the migration directory. Because Python executes module-level statements during import, the attacker-controlled module is executed automatically by the application runtime.

Execution was verified through creation of a proof artifact inside the container.

Affected Endpoint

POST /api/v1/datasource/parseExcel

Root Cause Analysis

The observed code execution is not caused by a single isolated flaw.

Instead, multiple independent weaknesses combine to create the final impact.

The following sections explain how each weakness contributes to the attack chain.

Vulnerability 1 — User-Controlled Filename Handling

The parseExcel endpoint accepts filenames supplied by the client during multipart uploads.

Normally, uploaded spreadsheet files should be stored inside a dedicated upload directory using a server-generated filename.

During testing, however, the application accepted a filename referencing an application-controlled directory rather than a normal spreadsheet filename.

Example:

Expected:
report.xlsx

Observed:
/opt/sqlbot/app/alembic/versions/migration.py.csv

Instead of treating the supplied value as a simple filename, the application uses attacker-controlled path information during file storage.

This demonstrates that the upload handler trusts attacker-supplied filename information and allows it to influence the final storage location.

Because the filename originates from the client, an attacker can attempt to target sensitive application directories instead of normal upload locations.

Vulnerability 2 — Arbitrary File Write

The upload handler writes attacker-controlled content to disk before spreadsheet parsing and validation complete.

Observed behavior:

Upload Request

File Written To Disk

Spreadsheet Parsing

Parser Error Returned

Even though the server eventually rejects the content as an invalid spreadsheet, the uploaded file remains present on disk.

Observed server response:

HTTP/1.1 500 Internal Server Error

Excel file format cannot be determined,
you must specify an engine manually.

This behavior demonstrates that the parser error does not prevent the filesystem write operation.

As a result, a failed upload request still produces a successful arbitrary file write.

Vulnerability 3 — Extension Confusion

Testing showed that an uploaded filename such as:

migration.py.csv

is ultimately stored as:

migration_.py

This behavior is significant because the resulting file is no longer treated as a spreadsheet.

Instead, the application creates a Python source file.

The resulting file extension changes the security impact dramatically because attacker-controlled content becomes executable Python code if it is written into a location later processed by the application.

Vulnerability 4 — Write Into Trusted Application Directories

The attacker-controlled file can be written into directories used by application components.

Observed target directory:

/opt/sqlbot/app/alembic/versions/

Observed result:

Attacker-controlled Python source file stored
inside the Alembic migration directory.

This directory is not merely a storage location.

It is a trusted application directory used by the Alembic migration framework.

Files stored within this directory are processed by application startup and migration operations.

Because the uploaded file is written into a trusted application directory, the impact extends beyond arbitrary file creation and becomes a code execution concern.

Vulnerability 5 — Trusted Import Path Abuse

Alembic stores migration modules inside:

/opt/sqlbot/app/alembic/versions/

A typical migration file contains metadata such as:

revision = "123"
down_revision = "456"

To obtain this information, Alembic imports migration modules during startup and migration processing.

Python executes module-level statements immediately during import.

For example:

print("Imported")
revision = "123"

The print() statement executes automatically when the module is imported.

As a result, any attacker-controlled Python file placed into the migration directory may execute automatically when the application performs migration processing.

Why Code Execution Occurs

The uploaded file does not execute immediately when the request is sent.

The request only plants a persistent Python file inside the Alembic migration directory.

Observed attack flow:

Attacker Upload

File Written To Alembic Directory

Spreadsheet Parsing Fails

Application Returns HTTP 500

File Remains On Disk

Application Restart

SQLBot Startup

Alembic Migration Processing

Python Module Import

Module-Level Code Execution

The critical observation is that the uploaded file remains persistent on disk after the request completes.

Execution occurs later because SQLBot performs migration processing during application startup.

In the tested environment, restarting the SQLBot container caused Alembic to import the uploaded module from the versions directory.

The import operation triggered execution of the module-level code contained within the uploaded file, resulting in creation of a proof artifact.

This behavior demonstrates that the vulnerability is not limited to arbitrary file creation and can lead to execution of attacker-controlled code.

Severity Justification

This issue should be considered High to Critical severity because it combines multiple weaknesses into a single attack chain.

An attacker can:

Control the uploaded filename.

Write files outside the intended upload location.

Create Python source files.

Place files into trusted application directories.

Persist files across requests.

Trigger execution during normal application startup.

The observed behavior transforms a file upload issue into a code execution pathway through existing application functionality.

Proof of Concept

Evidence (In Order)
  1. Version Confirmation 1.Version.png
image

Confirms SQLBot Community Edition v1.8.0 was used during testing.

  1. Crafted parseExcel Upload Request 2.Burp-Request.png
image
  1. File Written To Alembic Directory 3.Docker-FileWrite.png
image

This confirms successful file creation within the migration directory.

  1. Application Restart

The SQLBot Docker container is restarted.

During startup, Alembic migration processing occurs.

Migration modules are imported by Python.

  1. Execution Verification 4.Execution-Proof.png
image

Observed contents:

The artifact demonstrates that the uploaded Python module executed within the SQLBot runtime environment.

Example vulnerable request
POST /api/v1/datasource/parseExcel HTTP/1.1
Host: localhost:7777
Cache-Control: max-age=0 sec-ch-ua: "Not;A=Brand";v="99", "Chromium";v="106" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Linux" Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5249.62 Safari/537.36
Accept: / X-SQLBOT-TOKEN: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiYWNjb3VudCI6ImFkbWluIiwib2lkIjoxLCJleHAiOjE3ODA4NTc4MjF9.XCQfGPfDM3hnnkUWwVgwwgxkqeY41r_S-ttNa3nngX8 Content-Length: 905 Content-Type: multipart/form-data;

boundary=------------------------mCTIZcglNvPuivxlOGf3ar
Connection: close

--------------------------mCTIZcglNvPuivxlOGf3ar
Content-Disposition: form-data; name="file";
filename="/opt/sqlbot/app/alembic/versions/nova.py.csv"
Content-Type: application/octet-stream import os, socket, datetime, sys try: with open("/tmp/cmdexecution-poc.txt","w") as f: f.write( "F-002 -> parseExcel path-traversal -> alembic-import -> RCE\n" f"pid={os.getpid()} uid={os.getuid()} host={socket.gethostname()}\n" f"py={sys.executable}\n" f"executed_at={datetime.datetime.utcnow().isoformat()}Z\n" "Planted via /api/v1/datasource/parseExcel (NOT uploadExcel) to prove the chain applies to BOTH endpoints.\n") except: pass revision = "ffff_f002b_rce" down_revision = None branch_labels = None depends_on = None def upgrade(): pass def downgrade(): pass

--------------------------mCTIZcglNvPuivxlOGf3ar--
Example vulnerable Response
HTTP/1.1 500 Internal Server Error
date: Sat, 30 May 2026 18:47:23 GMT
server: uvicorn
access-control-allow-origin: *
content-length: 78
content-type: application/json
connection: close

"Excel file format cannot be determined, you must specify an engine manually.”

Affected versions
< v1.9.0

Patches

The vulnerability has been fixed in v1.9.0.

Workarounds

It is recommended to upgrade the version to v1.9.0.

References

If you have any questions or comments about this advisory:

Open an issue in https://github.com/dataease/sqlbot
Email us at wei@fit2cloud.com

Severity

High

CVE ID

CVE-2026-53554

Weaknesses

No CWEs

Credits