CVE-2026-86258 Overview
CVE-2026-86258 is a path traversal vulnerability [CWE-22] in nbviewer through version 1.0.1, the Jupyter project's notebook rendering service. The flaw resides in the LocalFileHandler.can_show() method, which uses a string-prefix comparison instead of proper path containment validation. Remote attackers can request paths that share the configured root directory as a textual prefix. This allows reading files from sibling directories outside the intended root. The disclosed content can include unintended notebooks and credentials stored on the server filesystem. Exploitation requires no authentication and can be performed over the network against any exposed nbviewer instance.
Critical Impact
Unauthenticated attackers can read arbitrary files from sibling directories outside the configured nbviewer root, exposing notebooks and credentials.
Affected Products
- Jupyter nbviewer versions through 1.0.1
- Deployments using the LocalFileHandler provider
- Self-hosted nbviewer instances exposing local filesystem content
Discovery Timeline
- 2026-09-06 - CVE-2026-86258 published to NVD
- 2026-09-10 - Last updated in NVD database
Technical Details for CVE-2026-86258
Vulnerability Analysis
The vulnerability exists in nbviewer/providers/local/handlers.py at lines 92-107. The can_show() method validates that a normalized request path stays within the configured localfile_path root. The check calls fullpath.startswith(self.localfile_path) on the resolved path string. String-prefix comparison is not equivalent to filesystem path containment. A configured root of /srv/notebooks will match /srv/notebooks-private/secret.ipynb because the target path shares the root string as a prefix. Attackers exploit this discrepancy to escape the intended directory boundary. The result is unauthorized read access to files in adjacent directories on the same filesystem.
Root Cause
The root cause is improper path validation. Path containment must be enforced on directory boundaries, not raw string prefixes. Without appending a trailing separator to both sides of the comparison, any directory whose name begins with the same characters as the configured root satisfies the check. The fix normalizes the root by stripping any trailing separator and appending os.sep, then compares against fullpath + os.sep to guarantee segment-aligned containment.
Attack Vector
An unauthenticated remote attacker crafts an HTTP request to the nbviewer local file endpoint. The requested path resolves via os.path.normpath to an absolute path that shares the configured root as a textual prefix but resides in a sibling directory. The handler returns the content of the targeted file. No user interaction is required.
os.path.normpath(os.path.join(self.localfile_path, path))
)
- if not fullpath.startswith(self.localfile_path):
+ prefix = self.localfile_path.rstrip(os.sep) + os.sep
+ if not (fullpath + os.sep).startswith(prefix):
self.log.warn("Directory traversal attempt: '%s'" % fullpath)
return False
Source: GitHub nbviewer Commit aad36106 — the patch enforces separator-aligned containment by appending os.sep to both the root prefix and the resolved path before comparison.
Detection Methods for CVE-2026-86258
Indicators of Compromise
- Web server access logs containing requests to nbviewer local file routes with paths that resolve outside the configured localfile_path root.
- Warning log entries generated by nbviewer containing the string Directory traversal attempt: followed by absolute paths.
- HTTP 200 responses returning notebook or file content from paths that reference sibling directories of the configured root.
Detection Strategies
- Inspect nbviewer application logs for Directory traversal attempt warnings emitted by can_show(), which indicate probing activity.
- Correlate HTTP request URIs against the configured localfile_path to identify responses served from paths that share the root as a string prefix but reside in adjacent directories.
- Deploy web application firewall rules that reject requests whose normalized path components attempt to escape the intended notebook root.
Monitoring Recommendations
- Enable verbose logging on nbviewer instances and forward application logs to a centralized SIEM for retention and query.
- Monitor read access patterns on directories adjacent to the configured nbviewer root, particularly directories that share a common name prefix.
- Alert on outbound responses from nbviewer that contain sensitive file extensions such as .env, .pem, .key, or credential-bearing configuration files.
How to Mitigate CVE-2026-86258
Immediate Actions Required
- Upgrade nbviewer to a version containing commit aad36106f72a1ca7721310c6fccc677ce4c744a5 or later, which enforces separator-aligned path containment.
- Restrict network exposure of nbviewer instances by placing them behind authenticated reverse proxies or internal-only networks.
- Audit the parent directory of localfile_path and remove or relocate any sibling directories that begin with the same name prefix as the configured root.
Patch Information
The upstream fix is available in the Jupyter nbviewer repository. The patch modifies nbviewer/providers/local/handlers.py to construct a prefix by stripping trailing separators from self.localfile_path and appending os.sep, then comparing fullpath + os.sep against that prefix. Review the GitHub nbviewer Commit Details, the GitHub nbviewer Issue Tracker, and the VulnCheck Advisory for nbviewer for authoritative technical details.
Workarounds
- Rename the configured localfile_path directory so that no sibling directory shares its name as a textual prefix.
- Isolate nbviewer within a chroot, container, or dedicated filesystem mount that contains only files intended for public rendering.
- Apply the two-line patch manually to nbviewer/providers/local/handlers.py if an official release upgrade is not immediately possible.
# Configuration example: run nbviewer in an isolated directory tree
mkdir -p /srv/nbviewer-root
chown -R nbviewer:nbviewer /srv/nbviewer-root
chmod 750 /srv/nbviewer-root
# Ensure no sibling directories share the prefix
ls -la /srv/ | grep '^d' | awk '{print $NF}' | grep '^nbviewer-root'
# Start nbviewer pinned to the isolated root
nbviewer --localfiles=/srv/nbviewer-root
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.