Skip to main content

Fickling

Fickling image

Fickling is a decompiler, static analyzer, and bytecode rewriter for Python pickle object serializations. You can use fickling to detect, analyze, reverse engineer, or even create malicious pickle or pickle-based files, including PyTorch files.

Fickling can be used both as a python library and a CLI.

Installation

Fickling has been tested on Python 3.9 through Python 3.13 and has very few dependencies. Both the library and command line utility can be installed through pip or uv:

# Using pip
python -m pip install fickling

# Using uv
uv pip install fickling

PyTorch is an optional dependency of Fickling. Therefore, in order to use Fickling's pytorch and polyglot modules, you should run:

# Using pip
python -m pip install fickling[torch]

# Using uv
uv pip install fickling[torch]

Securing AI/ML environments

Fickling can help securing AI/ML codebases by automatically scanning pickle files contained in models. Fickling hooks the pickle module and verifies imports made when loading a model. It only checks the imports against an allowlist of imports from ML libraries that are considered safe, and blocks files that contain other imports.

To enable Fickling security checks simply run the following lines once in your process, before loading any AI/ML models:

import fickling
# This sets global hooks on pickle
fickling.hook.activate_safe_ml_environment()

To remove the protection:

fickling.hook.deactivate_safe_ml_environment()

It is possible that the models you are using contain imports that aren't allowed by Fickling. If you still want to load the model, you can simply allow additional imports for your specific use-case with the also_allow argument:

fickling.hook.activate_safe_ml_environment(also_allow=[
    "some.import",
    "another.allowed.import",
])

Important: You should always make sure that manually added imports are actually safe and can not enable attackers to execute arbitrary code. If you are unsure on how to do that, you can open an issue on Fickling's Github repository that indicates the imports/models in question, and our team can review them and include them in the allow list if possible.

Generic malicious file detection

Fickling can seamlessly be integrated into your codebase to detect and halt the loading of malicious files at runtime.

Below we show the different ways you can use fickling to enforce safety checks on pickle files. Under the hood, it hooks the pickle library to add safety checks so that loading a pickle file raises an UnsafeFileError exception if malicious content is detected in the file.

Option 1 (recommended): check safety of all pickle files loaded

# This enforces safety checks every time pickle is used to deserialize
fickling.always_check_safety()

# Attempt to load an unsafe file now raises an exception
with open("file.pkl", "rb") as f:
    try:
        pickle.load(f)
    except fickling.UnsafeFileError:
        print("Unsafe file!")

Option 2: use a context manager

with fickling.check_safety():
    # All pickle files loaded within the context manager are checked for safety
    try:
        with open("file.pkl", "rb") as f:
            pickle.load("file.pkl")
    except fickling.UnsafeFileError:
        print("Unsafe file!")

# Files loaded outside of context manager are NOT checked
pickle.load("file.pkl")

Option 3: check and load a single file

# Use fickling.load() in place of pickle.load() to check safety and load a single pickle file
try:
    fickling.load("file.pkl")
except fickling.UnsafeFileError as e:
    print("Unsafe file!")

Option 4: only check pickle file safety without loading

# Perform a safety check on a pickle file without loading it
if not fickling.is_likely_safe("file.pkl"):
    print("Unsafe file!")

Accessing the safety analysis results

You can access the details of fickling's safety analysis from within the raised exception:

>>> try:
...     fickling.load("unsafe.pkl")
... except fickling.UnsafeFileError as e:
...     print(e.info)

{
    "severity": "OVERTLY_MALICIOUS",
    "analysis": "Call to `eval(b'[5, 6, 7, 8]')` is almost certainly evidence of a malicious pickle file. Variable `_var0` is assigned value `eval(b'[5, 6, 7, 8]')` but unused afterward; this is suspicious and indicative of a malicious pickle file",
    "detailed_results": {
        "AnalysisResult": {
            "OvertlyBadEval": "eval(b'[5, 6, 7, 8]')",
            "UnusedVariables": [
                "_var0",
                "eval(b'[5, 6, 7, 8]')"
            ]
        }
    }
}

If you are using another language than Python, you can still use fickling's CLI to safety-check pickle files:

fickling --check-safety -p pickled.data

Advanced usage

Trace pickle execution

Fickling's CLI allows to safely trace the execution of the Pickle virtual machine without exercising any malicious code:

fickling --trace file.pkl

Pickle code injection

Fickling allows to inject arbitrary code in a pickle file that will run every time the file is loaded

fickling --inject "print('Malicious')" file.pkl > malicious.pkl

Pickle decompilation

Fickling can be used to decompile a pickle file for further analysis

>>> import ast, pickle
>>> from fickling.fickle import Pickled
>>> fickled_object = Pickled.load(pickle.dumps([1, 2, 3, 4]))
>>> print(ast.dump(fickled_object.ast, indent=4))
Module(
    body=[
        Assign(
            targets=[
                Name(id='result', ctx=Store())],
            value=List(
                elts=[
                    Constant(value=1),
                    Constant(value=2),
                    Constant(value=3),
                    Constant(value=4)],
                ctx=Load()))],
    type_ignores=[])

PyTorch polyglots

PyTorch contains multiple file formats with which one can make polyglot files, which are files that can be validly interpreted as more than one file format. Fickling supports identifying, inspecting, and creating polyglots with the following PyTorch file formats:

  • PyTorch v0.1.1: Tar file with sys_info, pickle, storages, and tensors
  • PyTorch v0.1.10: Stacked pickle files
  • TorchScript v1.0: ZIP file with model.json
  • TorchScript v1.1: ZIP file with model.json and attributes.pkl
  • TorchScript v1.3: ZIP file with data.pkl and constants.pkl
  • TorchScript v1.4: ZIP file with data.pkl, constants.pkl, and version set at 2 or higher (2 pickle files and a folder)
  • PyTorch v1.3: ZIP file containing data.pkl (1 pickle file)
  • PyTorch model archive format[ZIP]: ZIP file that includes Python code files and pickle files
>> import torch
>> import torchvision.models as models
>> from fickling.pytorch import PyTorchModelWrapper
>> model = models.mobilenet_v2()
>> torch.save(model, "mobilenet.pth")
>> fickled_model = PyTorchModelWrapper("mobilenet.pth")
>> print(fickled_model.formats)
Your file is most likely of this format:  PyTorch v1.3
['PyTorch v1.3']

Check out our examples to learn more about using fickling!

More information

Pickled Python objects are in fact bytecode that is interpreted by a stack-based virtual machine built into Python called the "Pickle Machine". Fickling can take pickled data streams and decompile them into human-readable Python code that, when executed, will deserialize to the original serialized object. This is made possible by Fickling’s custom implementation of the PM. Fickling is safe to run on potentially malicious files because its PM symbolically executes code rather than overtly executing it.

The authors do not prescribe any meaning to the “F” in Fickling; it could stand for “fickle,” … or something else. Divining its meaning is a personal journey in discretion and is left as an exercise to the reader.

Learn more about fickling in our blog post and DEF CON AI Village 2021 talk.

Contact

If you'd like to file a bug report or feature request, please use our issues page. Feel free to contact us or reach out in Empire Hacking for help using or extending fickling.

License

This utility was developed by Trail of Bits. It is licensed under the GNU Lesser General Public License v3.0. Contact us if you're looking for an exception to the terms.

© 2021, Trail of Bits.

Release files for fickling 0.1.12

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fickling 0.1.12
File Size Uploaded
fickling-0.1.12.tar.gz 357.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fickling 0.1.12
File Interpreter ABI Platform
fickling-0.1.12-py3-none-any.whl Python 3 none any Details

Total release size: 416.0 kB

Release files / fickling-0.1.12.tar.gz

Download URL fickling-0.1.12.tar.gz
Size 357.0 kB
Tags Source
SHA-256 checksum
How to use checksums
83f6ccc948e21edb9ebd92795069536b47f481ce6add62598eac608b31576821
BLAKE2b-256 checksum
How to use checksums
d720d3c2bdb9235b777763a4afc7cc3673afcd162a707ec0988ae7141a540802
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 26, 2026.

Transparency log

Release files / fickling-0.1.12-py3-none-any.whl

Download URL fickling-0.1.12-py3-none-any.whl
Size 59.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6232b72857e6ee9d729922811b681132d49dc39abc896581390dad1c0eada814
BLAKE2b-256 checksum
How to use checksums
bac0c65003b71abc4ffddbae99ae86952a21ff859d81b0f1331f79239fe5a58e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.12 This release

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page