The safe_extract_tarfile() function validates that each tar member's path is within the destination directory, but for symlink members it only validates the symlink's own path, not the symlink's target. An attacker can create a malicious bento/model tar file containing a symlink pointing outside the extraction directory, followed by a regular file that writes through the symlink, achieving arbitrary file write on the host filesystem.
src/bentoml/_internal/utils/filesystem.py:58-96src/bentoml/_internal/cloud/bento.py:542, src/bentoml/_internal/cloud/model.py:504safe_extract_tarfile()CVSS 3.1: 8.1 (High)
AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H
def safe_extract_tarfile(tar, destination):
os.makedirs(destination, exist_ok=True)
for member in tar.getmembers():
fn = member.name
path = os.path.abspath(os.path.join(destination, fn))
if not Path(path).is_relative_to(destination): # Line 64: INCOMPLETE
continue # Only checks member path, NOT symlink target
if member.issym():
tar._extract_member(member, path) # Line 75: Creates symlink with UNVALIDATED target
else:
fp = tar.extractfile(member)
with open(path, "wb") as destfp: # Line 92: open() FOLLOWS symlinks
shutil.copyfileobj(fp, destfp)
Path(path).is_relative_to(destination) checks the member's OWN path, not the symlink targettar._extract_member() creates symlink with unvalidated target (e.g., /etc)open(path, "wb") follows the symlink, writing OUTSIDE the destinationos.path.abspath() does NOT resolve symlinks (only . and ..). The path check passes because...
1.4.36Exploitability
AV:LAC:LAT:NPR:NUI:NVulnerable System
VC:HVI:HVA:HSubsequent System
SC:NSI:NSA:N8.6/CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N