From c56e099660c2a3a58ed69152d9ae779dfaacbabe Mon Sep 17 00:00:00 2001 From: massy-o Date: Thu, 14 May 2026 15:58:35 +0900 Subject: [PATCH] Detect mailcap findmatch pickle payloads --- modelscan/settings.py | 3 +++ tests/test_pickle_unsafe_globals.py | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 tests/test_pickle_unsafe_globals.py diff --git a/modelscan/settings.py b/modelscan/settings.py index 56b3a796..542e434b 100644 --- a/modelscan/settings.py +++ b/modelscan/settings.py @@ -130,6 +130,9 @@ class SupportedModelFormats: "pdb": "*", "shutil": "*", "asyncio": "*", + "mailcap": [ + "findmatch", # mailcap.findmatch executes matching entry test commands via os.system() + ], }, "HIGH": { "webbrowser": "*", # Includes webbrowser.open() diff --git a/tests/test_pickle_unsafe_globals.py b/tests/test_pickle_unsafe_globals.py new file mode 100644 index 00000000..9bdafe14 --- /dev/null +++ b/tests/test_pickle_unsafe_globals.py @@ -0,0 +1,25 @@ +import pickle +from typing import Any + +from modelscan.modelscan import ModelScan + + +class MaliciousMailcapFindmatch: + def __reduce__(self) -> Any: + import mailcap + + caps = {"text/plain": [{"view": "cat %s", "test": "true"}]} + return mailcap.findmatch, (caps, "text/plain") + + +def test_scan_flags_mailcap_findmatch(tmp_path) -> None: + path = tmp_path / "mailcap.pkl" + path.write_bytes(pickle.dumps(MaliciousMailcapFindmatch())) + + modelscan = ModelScan() + results = modelscan.scan(path) + + assert results["summary"]["scanned"]["scanned_files"] == ["mailcap.pkl"] + assert results["summary"]["total_issues"] == 1 + assert modelscan.issues.all_issues[0].details.module == "mailcap" + assert modelscan.issues.all_issues[0].details.operator == "findmatch"