Path-Traversal -> Arbitrary File Write in Assemblyline Service Client
The Assemblyline 4 service client (task_handler.py
) accepts a SHA-256 value returned by the service server and uses it directly as a local file name.
No validation / sanitisation is performed.
A malicious or compromised server (or any MITM that can speak to client) can return a path-traversal payload such as
../../../etc/cron.d/evil
and force the client to write the downloaded bytes to an arbitrary location on disk.
| Item | Value |
|---|---|
| Component | assemblyline-service-client
|
| Repository | CybercentreCanada/assemblyline-service-client |
| Affected | All releases up to master branch. |
| Field | Content |
|---|---|
| Location | assemblyline_service_client/task_handler.py
, inside download_file()
|
| Vulnerable Line | file_path = os.path.join(self.tasking_dir, sha256)
|
| Root Cause | The sha256
string is taken directly from the service-server JSON response and used as a file name without any validation or sanitisation. |
| Exploit Flow | 1. Attacker (service server) returns HTTP 200 for GET /api/v1/file/../../../etc/cron.d/evil
.<br>2. Client writes the response body to /etc/cron.d/evil
.<br>3. Achieves arbitrary file write (code execution if file is executable). |
import re
_SHA256_RE = re.compile(r'^[0-9a-fA-F]{64}\Z')
def download_file(self, sha256: str, sid: str) -> Optional[str]:
if not _SHA256_RE.fullmatch(sha256):
self.log.error(f"[{sid}] Invalid SHA256: {sha256}")
self.status = STATUSES.ERROR_FOUND
return None
# or your preferred way to check if a string is a shasum.
{ "github_reviewed": true, "severity": "CRITICAL", "github_reviewed_at": "2025-07-25T14:15:48Z", "cwe_ids": [ "CWE-23" ], "nvd_published_at": null }