#821·zfile

[Security] Proxy Download Path Isolation Bypass + Path Traversal Protection Bypass

Author: icysunCreated May 7, 2026Updated Aug 9, 2026

Proxy Download Path Isolation Bypass in zfile

CVE Request: Pending
CVSS: 6.5 (Medium) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Discovery Date: 2026-03-31
Affected Component: LocalServiceImpl.java, proxy download endpoint /pd/{storageKey}/**
Reporter: icysun <[email protected]>


Summary

A path isolation bypass vulnerability exists in zfile's proxy download functionality. The downloadToStream() method in LocalServiceImpl.java does not prepend getCurrentUserBasePath() when resolving file paths, unlike all other file operations (fileList, uploadFile, deleteFile, etc.). This allows an attacker to construct proxy download URLs that skip the per-user directory prefix, accessing files from other users' storage paths or the raw storage root directly.

When proxyPrivate=false (signature verification disabled), this bypass is exploitable without authentication, enabling unauthenticated access to all files managed by zfile under the affected storage source.

Root Cause

The root cause is an inconsistency in path resolution between file listing and file download operations.

Vulnerable Code — LocalServiceImpl.java (line ~283)

java
// downloadToStream() — MISSING getCurrentUserBasePath()
String fullPath = concat(param.getFilePath(), pathAndName);

Secure Reference — fileList() (contrast)

java
// fileList() — CORRECTLY includes getCurrentUserBasePath()
String fullPath = concat(param.getFilePath(), getCurrentUserBasePath(), folderPath);

The getProxyDownloadUrl() method generates URLs that include getCurrentUserBasePath() via fileToFileItem(), so the normal frontend flow works correctly. However, since downloadToStream() does not re-validate or re-apply the basePath, an attacker who manually constructs a proxy download URL without the basePath component bypasses the isolation entirely.

Attack Path

Prerequisites

  1. proxyPrivate=false on the target storage source (signature verification disabled), OR a valid AES signature obtained through legitimate access.
  2. Knowledge of the storage source key (visible in the zfile admin panel or URL patterns).

Steps

  1. Identify the storage key — Observe the proxy download URL pattern /pd/{storageKey}/... or extract from the admin interface.
  2. Determine user basePath — Normal users receive URLs like /pd/{key}/{userBasePath}/{file}. The attacker's basePath differs from other users'.
  3. Construct a bypass URL — Request /pd/{key}/{targetUserBasePath}/{sensitiveFile} or /pd/{key}/{fileAtStorageRoot}, omitting the attacker's own basePath.
  4. Retrieve files — The server resolves the path directly against param.getFilePath() without enforcing user isolation.

Example

Normal user A download URL:
  /pd/local01/userA/documents/report.pdf
  → Resolves to: /storage/root/userA/documents/report.pdf ✓

Attacker bypass URL (accessing user B's files):
  /pd/local01/userB/secret.txt
  → Resolves to: /storage/root/userB/secret.txt ✓ (ISOLATION BYPASSED)

Attacker bypass URL (storage root):
  /pd/local01/config.yml
  → Resolves to: /storage/root/config.yml ✓ (ISOLATION BYPASSED)

PoC

A fully functional exploit script is provided: exploit_zfile_proxy_bypass.py

Verification

bash
# Check if signature verification is enforced
python3 exploit_zfile_proxy_bypass.py \
  --target http://target:8080 \
  --storage-key local01 \
  --verify

Brute-force sensitive files

bash
# Enumerate common sensitive files at storage root
python3 exploit_zfile_proxy_bypass.py \
  --target http://target:8080 \
  --storage-key local01 \
  --bruteforce

Read a specific file

bash
# Access another user's file directly
python3 exploit_zfile_proxy_bypass.py \
  --target http://target:8080 \
  --storage-key local01 \
  --read /otherUser/secret.txt

Impact

  • Confidentiality Impact: HIGH — An attacker can read any file accessible to zfile's storage backend, including files belonging to other users.
  • Integrity Impact: NONE — This is a read-only vulnerability.
  • Availability Impact: NONE — No denial-of-service vector.

Affected Deployments

  • Multi-user zfile instances where proxyPrivate=false (default or intentionally set) are fully exploitable without authentication.
  • Instances with proxyPrivate=true require a valid signature, but the vulnerability still allows accessing other users' files once a signature is obtained through any legitimate user session.
  • All storage types using LocalServiceImpl are affected.

Remediation

Recommended Fix

Apply getCurrentUserBasePath() prefix in downloadToStream(), consistent with other file operations:

java
// Before (vulnerable):
String fullPath = concat(param.getFilePath(), pathAndName);

// After (fixed):
String fullPath = concat(param.getFilePath(), getCurrentUserBasePath(), pathAndName);

Defense in Depth

  1. Validate basePath in download handler — The proxy download controller should extract the basePath from the signed URL and verify it matches the requesting user's basePath.
  2. Re-signature verification — Ensure that even if proxyPrivate=false, the download path is validated against the user's authorized path prefix.
  3. Audit log — Log proxy download accesses with user identity and requested path for anomaly detection.

Workaround

Set proxyPrivate=true on all storage sources. This requires a valid AES signature for proxy downloads, limiting exploitation to authenticated users who can obtain a signature (though the isolation bypass still exists within that scope).

CVE Request

A CVE identifier is requested for this vulnerability. This is a distinct path isolation bypass (missing authorization prefix) separate from path traversal protections.

Justification

  • Exploitable over the network without authentication (when proxyPrivate=false)
  • Affects all multi-user deployments of zfile
  • Allows reading files from other users' storage paths
  • Consistent with CVSS 6.5 (Medium severity)

Reporter

Field Value
Name icysun
Email [email protected]
Date 2026-03-31

This report was prepared for responsible disclosure. The zfile project does not maintain a SECURITY.md or dedicated security contact. This report is saved locally pending identification of a disclosure channel.