Skip to content

security: add importlib and marshal to _unsafe_globals blocklist#74

Closed
Ashutosh0x wants to merge 1 commit into
mmaitre314:mainfrom
Ashutosh0x:fix/add-importlib-marshal-to-unsafe-globals
Closed

security: add importlib and marshal to _unsafe_globals blocklist#74
Ashutosh0x wants to merge 1 commit into
mmaitre314:mainfrom
Ashutosh0x:fix/add-importlib-marshal-to-unsafe-globals

Conversation

@Ashutosh0x
Copy link
Copy Markdown

Summary

importlib and marshal are missing from the _unsafe_globals blocklist, allowing attackers to craft malicious pickle files that completely evade picklescan detection.

Attack Vectors

importlib bypass

class Exploit:
    def __reduce__(self):
        return importlib.import_module, ("os",)

importlib.import_module() can dynamically import any module at unpickle time, completely bypassing the entire blocklist. An attacker chains this with getattr to call arbitrary functions (e.g., os.system).

marshal bypass

class Exploit:
    def __reduce__(self):
        code = compile("os.system('malicious')", "<s>", "exec")
        return marshal.loads, (marshal.dumps(code),)

marshal.loads() deserializes arbitrary code objects from raw bytes, enabling direct code execution without triggering any module-level detection.

Fix

Added both importlib and marshal as wildcard ("*") entries in _unsafe_globals, since all their public functions pose security risks during deserialization.

Tests

  • Added importlib_bypass.pkl and marshal_bypass.pkl test fixtures
  • Added corresponding assert_scan assertions in test_scan_file_path
  • All existing tests continue to pass

Related

CC: @mmaitre314

importlib.import_module() can dynamically import any module at unpickle
time, completely bypassing the blocklist (e.g., importing os, subprocess,
etc. indirectly). marshal.loads() can deserialize arbitrary code objects
from raw bytes, enabling direct code execution without triggering any
module-level detection.

Both modules are marked as wildcard ('*') dangerous since all their
public functions pose security risks when invoked during deserialization.

Includes test pickle files and test assertions for both bypass vectors.
@Ashutosh0x
Copy link
Copy Markdown
Author

Hey @mmaitre314 - this PR adds importlib and marshal to the _unsafe_globals blocklist. Both modules allow complete scanner evasion: importlib.import_module() can dynamically import any blocked module (e.g. os, subprocess), and marshal.loads() can deserialize arbitrary code objects from bytes. I discovered these bypasses while testing picklescan and reported them via huntr.com. The fix is minimal (2 new wildcard entries) with test fixtures and assertions included. Happy to address any feedback!

@Ashutosh0x Ashutosh0x closed this by deleting the head repository May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant