ModelScan vs Fickling

ModelScan suits teams that need one scanner across several model formats in CI and before deployment. Fickling suits teams that want a load-time allowlist in front of pickle loading, such as torch.load.

On this page

ModelScan vs Fickling: when each one fits

A team that downloads or receives pre-trained model files has to decide which checks run before a file is loaded. ModelScan fits a multi-format scan gate in CI and pipelines, and Fickling fits a load-time allowlist hook in front of pickle loading. The two tools answer different questions. ModelScan asks whether a file contains unsafe code across many formats before it moves forward. Fickling asks whether each pickle load touches only imports on a list the team has approved, and it raises an error when it does not.

Three questions decide between them. The first is where the check must sit. ModelScan's README recommends scanning before loading pre-trained models, after training and before deployment, which suits a gate that rejects artifacts before they reach a registry or serving path. Fickling's allowlist hook runs at the moment of loading, which suits code paths where a file could reach torch.load without passing through a pipeline step. The second is which formats the team handles. ModelScan covers PyTorch (Pickle), TensorFlow SavedModel and Protocol Buffer, Keras H5 and Keras V3, and classic ML formats saved with Pickle, Cloudpickle, Dill and Joblib. Fickling's documented coverage centers on plain pickles and PyTorch formats, including TorchScript and the PyTorch ZIP archive.

The third question is licensing. ModelScan is Apache-2.0 licensed, which most enterprise legal reviews accept without extra conditions. Fickling is licensed under LGPL-3.0, so confirm with counsel how your organization treats weak copyleft before embedding it in internal tooling or a distributed product. Whichever tool you choose, confirm current versions and Python support against your own environment, since ModelScan 0.8.8 supports Python 3.10 up to but not including 3.13 and Fickling 0.1.12 requires Python 3.10 or newer.

Which scanner fits which scenario

This table walks through illustrative scenarios and names the better starting point for each, based on formats, whether the check runs before a load or inside a pipeline, and the kind of output the team needs. Read it as a starting point for your own model intake policy, since neither tool covers every threat and some scenarios call for both.

Scenario (illustrative)Better fitWhy
Platform team scanning every model before it enters a registryModelScanModelScan covers PyTorch Pickle, TensorFlow SavedModel, Keras H5 and V3, and Pickle, Cloudpickle, Dill and Joblib files in one CLI run. It ranks findings by severity and returns nonzero exit codes, which suits a pipeline gate across mixed formats.
ML engineer loading one pickled checkpoint with torch.loadFicklingFickling can hook Python's pickle module so each load is checked against an allowlist of imports, raising UnsafeFileError on failure. This places the check at load time, directly in front of torch.load.
Team with Keras and TensorFlow model filesModelScanModelScan lists Keras H5, Keras V3 and TensorFlow SavedModel among its supported formats. Fickling's listed coverage centers on pickle and PyTorch formats, so confirm its fit for Keras artifacts before relying on it.
Security analyst who must inspect pickle opcodes by handFicklingFickling decompiles and symbolically executes pickles without running them, so an analyst can read the reconstructed logic. ModelScan reports byte-signature findings and does not give a decompiled view of the file.
Team that needs a verdict on a file from an external source before any tooling touches itFicklingBoth tools analyze without executing embedded code. Fickling's decompilation helps an analyst explain why a file is suspicious, while ModelScan's severity labels suit triage queues. Confirm the workflow your analysts need before choosing.
Compliance lead who needs a documented scan step for model intakeModelScanModelScan's README recommends scanning before loading pre-trained models, after training and before deployment, which maps to a documented intake checkpoint. Confirm with your assessor which evidence format they expect from the scan output.
Team relying on Hugging Face Hub checks aloneNeither as a replacementHugging Face runs its own pickle import scan and ClamAV on pushed files and says the scan is not foolproof. Local scanning with either tool adds a check you control, but neither tool covers every threat.
Team with a strict copyleft review policy on dependenciesModelScanModelScan is Apache-2.0, while Fickling is LGPL-3.0. Legal review decides whether LGPL linking is acceptable for your build, so confirm it with counsel before adding Fickling to a product pipeline.

How ModelScan and Fickling read pickle files differently

ModelScan and Fickling both look inside serialized model files without trusting them, but they answer different questions. The cards below cover how each reads a file, how each fits a pipeline or a load path, and who ends up owning the rules and the findings.

Byte-level signature reading

ModelScan reads model files byte by byte and looks for unsafe code signatures instead of loading them, so embedded code never runs. Because it matches patterns, its coverage is only as good as its signature set for the formats you handle. Ask the maintainers how signatures are added and tested, and run it against a file you know is malicious before you rely on it for a given format.

Symbolic execution for analysis

Fickling decompiles and statically analyzes pickles by symbolically executing them, so analysis does not run the file. This gives an analyst the reconstructed logic of a pickle, which is useful when a finding needs explaining. The cost is that someone must read that output, so plan for a reviewer with pickle and Python expertise rather than a pass or fail gate alone.

Allowlist hook at load time

Fickling can hook Python's pickle module so every load is checked against an allowlist of imports from ML libraries considered safe. A failed check raises UnsafeFileError, which stops the load inside your process. The allowlist is a policy decision: your team or a platform owner must decide which imports are acceptable, and must update that list when a legitimate model needs a new one.

CLI exit codes and Python API

ModelScan ranks findings as CRITICAL, HIGH, MEDIUM or LOW and offers a CLI with nonzero exit codes plus a Python API, so a scan can gate a CI/CD stage or a model registry import. Decide which severities block a pipeline and who may approve an exception. Fickling is used as a library or CLI, so the gating logic is usually something your team writes around its output.

Bytecode rewriting and test injection

Fickling can rewrite pickle bytecode and inject code into pickles for testing. For a security team, this is how to produce known-bad samples that check whether your scanners and load-time hooks actually fire. Hugging Face's Pickle Scanning documentation uses Fickling in the same way to show how code can be inserted. Keep these generated samples in a controlled test corpus, never in a production model store.

Who owns rules and findings

With ModelScan, the signature set and severity model come from the project, and your team owns the pipeline gate and exception process. With Fickling, your team owns the allowlist and the review of anything it flags. Name one owner for each list before rollout, and confirm the review path for disputed findings with your own security and ML teams.

Capabilities side by side from supplied facts

This table compares ModelScan and Fickling on formats, check placement, analysis method, output, CI fit, license and Python support, using only confirmed facts. Read each row against your own loading path: if models are pulled into a pipeline before use, the scanner fit differs from a check that runs inside every load call.

CapabilityModelScanFickling
Model formatsPyTorch Pickle, TensorFlow SavedModel and Protocol Buffer, Keras H5 and Keras V3, and classic ML formats saved with Pickle, Cloudpickle, Dill and JoblibPlain pickles, PyTorch formats including TorchScript versions and the PyTorch ZIP model archive
Check placementPipeline scan run before loading, after training and before deployment, as the README recommendsPickle module hook that checks every load against an import allowlist, or analysis run as a library or CLI
Analysis methodReads model files byte by byte for unsafe code signatures without loading themSymbolically executes pickles so analysis does not run them, and can decompile and rewrite bytecode
Severity outputRanks findings as CRITICAL, HIGH, MEDIUM or LOWRaises UnsafeFileError when an allowlist check fails; confirm with the vendor whether it grades findings by severity
CI integrationCLI with nonzero exit codes and a Python API for CI/CD pipelinesPython library and CLI; confirm with the vendor how exit codes and reports are produced for pipeline use
LicenseApache-2.0LGPL-3.0; confirm with your legal team what the LGPL terms require when you embed or modify the library
Python supportVersion 0.8.8 supports Python 3.10 up to but not including 3.13Version 0.1.12 requires Python 3.10 or newer

What the licenses and editions mean for each tool

ModelScan is released under the Apache-2.0 license by Protect AI. Apache-2.0 permits internal use, modification and redistribution, and it includes an express patent grant. Your obligations center on keeping license notices and attribution intact when you ship the code. A platform team can fork the scanner, add internal signatures or wrap it in a gateway without the copyleft duties that apply to some other licenses. Protect AI also sells a commercial product in the same space, so the open-source project and the vendor's offer are separate decisions.

  • Apache-2.0 terms: Internal modification and bundling into an internal image carry notice and attribution duties, but they do not require you to publish your own pipeline code.
  • Guardian as a separate offer: Protect AI describes Guardian as its enterprise model scanning product with newer scanners, broader model support and enforcement for Hugging Face models. Do not assume the open-source release has the same coverage.
  • Inspiration credit: The ModelScan README states that the project was heavily inspired by Matthieu Maitre's picklescan. That credit does not make the two tools interchangeable, so test both on your own model set.
  • Support terms: The supplied facts do not describe a paid support tier for the open-source project. Ask Protect AI whether support exists for the open-source release and what it covers.

Before approving ModelScan, confirm with Protect AI which Guardian capabilities you need and whether any of them require a commercial license, so the procurement record reflects what you will actually run.

What drives the running cost of each scanner

The largest cost in either tool is engineering time, and most of it is one-time setup. For ModelScan, that means wiring the CLI into a CI job so a nonzero exit code blocks a pipeline, and deciding which severities fail the build. For Fickling, it means placing the UnsafeFileError hook where every torch.load call in your code path passes through it, then writing the allowlist. Neither tool's fixed setup cost is published, so ask your implementation partner to estimate both from your pipeline layout and the number of model loading paths. A written quote should itemize these tasks separately so you can see which one dominates.

Recurring work is where the two tools diverge. A Fickling allowlist is a list of ML library imports you have judged safe, so every new library, new model architecture or new PyTorch release that introduces an import outside that list will fail a load until someone reviews it. Someone on your team owns that review queue. ModelScan's recurring cost is mostly triage: each CRITICAL or HIGH finding needs an analyst to confirm whether it is a true unsafe payload or a false positive, and to record the decision. Both tools also pin you to Python versions. Fickling 0.1.12 requires Python 3.10 or newer, and ModelScan 0.8.8 supports Python 3.10 up to but not including 3.13, so a Python upgrade on your base image may force a scanner upgrade or a rebuild.

Every upgrade of either scanner should trigger re-validation. Run your known-good and known-bad test models through the new version before it reaches production, and confirm the allowlist still behaves as expected. If your team pursues Protect AI's Guardian, which the ModelScan README describes as its enterprise scanning product, add the subscription cost, its licensing terms and any integration work to the recurring line. Ask any quote to state who maintains the allowlist, who performs triage, how upgrades are tested and whether Guardian is in or out of scope.

Moving from one scanner to the other without a gap in coverage

This sequence lets a team add Fickling beside ModelScan, or replace one with the other, while every model file keeps passing through a check at each load point. The output is a tested gate, a reconciled set of findings and a written record of what changed.

  1. Inventory model formats and load points

    The platform or ML engineering lead lists every model format the organization accepts, such as PyTorch pickle, TorchScript, PyTorch ZIP archives, Keras H5, Keras V3, TensorFlow SavedModel, and classic pickle, cloudpickle, dill or joblib files. For each format, record where it is loaded, including notebooks, training jobs, inference services and any direct calls to torch.load. Done means a table that maps every format to its load points and to the check that currently covers it, with uncovered formats marked clearly.

  2. Keep the existing gate running

    Leave the current scanner in every CI job and load path unchanged while the new tool is evaluated. Do not remove or relax any rule during the transition. Done means the current pipeline runs green on the same inputs as before, and the team has a recorded baseline of its current findings and exit codes to compare against later.

  3. Install the second tool in a parallel job

    The engineer adds Fickling, or ModelScan if it is the newcomer, as a separate, non-blocking CI job that scans the same artifacts. Confirm the runtime first: ModelScan 0.8.8 supports Python 3.10 up to but not including 3.13, and Fickling 0.1.12 requires Python 3.10 or newer. Done means the parallel job runs on the same Python version as the production gate and produces output for every format in the inventory.

  4. Reconcile findings on a known sample set

    Build a sample set that includes files known to be safe, files with embedded code that the team has already identified, and at least one example from each format in the inventory. Run both tools on every file and tabulate results side by side, noting where one flags a file the other passes. Investigate each disagreement by hand. Done means a written reconciliation that explains every mismatch, and a decision on whether each format is covered by a check that is acceptable to the security team.

  5. Update exit-code handling and the allowlist

    The engineer maps each tool's result to the pipeline's pass or fail behavior. ModelScan reports findings as CRITICAL, HIGH, MEDIUM or LOW and returns nonzero exit codes, so confirm which severities block a merge. Fickling's hook raises UnsafeFileError on a failed allowlist check, so the team decides which import allowlist entries apply to each library and records the reason for each one. Done means a reviewed configuration file with severity thresholds, exit-code mapping and allowlist entries, approved by the team that owns model intake.

  6. Promote the new check to blocking

    Once reconciliation is accepted, switch the new tool to a blocking gate in CI and add the load-time check in front of torch.load where Fickling's hook is used. Keep the old gate in place for one full release cycle as a fallback, then compare results from real intake. Done means that new merges and loads fail on the new check, and the team has seen at least one real intake pass through it without an unexplained result.

  7. Retire the old check and document the change

    Remove the superseded scanner from CI and load paths, and delete any allowlist entries or exemptions that existed only for it. Update the model intake procedure to name the surviving tools and their versions. Hugging Face notes that its own scan is not foolproof, so keep the procedure's wording clear that no single scanner is a complete control. Done means the repository contains a change record with the reconciliation results, the retired check and the owner of each remaining gate.

  8. Carry forward policy and rebuild the rest

    Policy, severity thresholds and the model inventory transfer directly, since they describe what the organization accepts rather than which tool checks it. CI jobs, allowlist entries and the license review are rebuilt: Fickling is LGPL-3.0 and ModelScan is Apache-2.0, so legal review should confirm how each is distributed and linked in your environment. Ask legal and procurement to confirm these terms before the new tool becomes blocking. Done means a signed-off list of transferred items and a separate list of rebuilt items with owners.

Where scanner implementations usually run long

Implementation work for either tool tends to stall in four places: Python environment alignment, ownership of allowlist and severity decisions, handling findings on legitimate files, and proving that the check runs before load. ModelScan 0.8.8 supports Python 3.10 up to but not including 3.13, and Fickling 0.1.12 requires Python 3.10 or newer, so confirm that your pinned interpreter satisfies both before you choose where each tool sits. If the same CI image also runs training or serving code on a newer interpreter, plan a separate scanning environment rather than discovering the conflict during a release.

Fickling's hook depends on an allowlist of imports, so someone must own that list. Decide who approves additions when a new model family introduces a class that is not yet trusted, who reviews a change to the list, and whether approvals are recorded in version control. ModelScan's severity ratings (CRITICAL, HIGH, MEDIUM and LOW) need the same kind of decision: which levels fail the pipeline, who may accept a finding, and how an exception expires. Confirm with each maintainer how their project expects these policies to be documented, and test the rules against a known-good model from your own registry.

Findings on legitimate files are the most common source of delay. A pickle that imports a utility from a trusted library can trigger a block, and each false positive needs a documented disposition rather than an ad hoc bypass. Ask whether your model types, including any custom Keras, Joblib or Dill artifacts, are covered by each tool at the depth you need. For auditors, record the scanner version, rule set and configuration, and capture a log showing that the scan or hook ran before torch.load or any deserialization call in the deployment path. Neither tool's supplied material is an attestation, so the evidence trail is your responsibility to design and test.

Questions teams ask before choosing a pickle scanner

Can ModelScan and Fickling run together in the same pipeline?

Yes, they can run together because they work at different points and answer different questions. ModelScan reads model files byte by byte for unsafe code signatures across several formats, including PyTorch pickles, TensorFlow SavedModel, Keras H5 and V3, and classic ML formats. Fickling symbolically analyzes pickles and can hook Python's pickle module so each torch.load call is checked against an import allowlist. A common layering is a ModelScan gate in CI and before deployment, with Fickling's allowlist applied where code loads model files. Confirm the exit behavior and the Python versions each tool supports in your own environment before you combine them in one job.

What can our own engineers do, and where does outside help add value?

Your engineers can install both tools, run them against a model registry, wire a nonzero exit code into CI and review findings. ModelScan's CLI and Python API are designed for this, and its README recommends scanning before loading pre-trained models, after training and before deployment. Outside help usually adds value in designing where the gates sit, writing the allowlist for your ML libraries, testing that a deliberately unsafe test file is blocked, and documenting the controls for an assessor. DeployOpen plans, implements, integrates and documents self-hosted platforms inside your infrastructure under a fixed-scope written agreement.

What drives the cost and effort of adding either scanner?

Cost comes from people time and the environment, not from either license, since both projects are open source. The main drivers are how many model sources you ingest, how many formats and Python versions your teams use, how many pipelines need a gate, and how much policy you need to write, such as which imports Fickling's allowlist permits. Ongoing effort recurs when you upgrade and retest after releases. Ask any partner for a quote that itemizes discovery, pipeline integration, allowlist design, testing, documentation and any retainer for upgrades.

Does Hugging Face's own scanning make a local scanner unnecessary?

No. Hugging Face scans every file pushed to the Hub with ClamAV and a pickle import scan that lists imports without executing them, but its own documentation says the scan is not foolproof. Files you download, copy from partners or receive from internal teams never pass through that scan again. A local gate lets you apply your own policy, record evidence and block a file before it reaches a training job or an inference service, so keep it even when you use the Hub.

Can Fickling's allowlist be enforced consistently across a team?

It can be enforced when the hook is installed in a shared, controlled place, such as a base image, a common library wrapper or a startup module that every training and serving job imports. Fickling's documentation describes hooking Python's pickle module to check every load against an allowlist and raising UnsafeFileError on failure. Individual developers who skip the import, or run code outside the shared image, bypass it. Treat the allowlist as code under review, test it against your library versions, and confirm the behavior with the Fickling maintainers for your Python version, since it requires Python 3.10 or newer.

What should our legal team confirm about LGPL-3.0 versus Apache-2.0?

Ask counsel to confirm how the LGPL-3.0 license of Fickling applies to your intended use, including whether you modify the library, bundle it into an internal image, or distribute it to customers or partners. ModelScan is Apache-2.0, which many organizations already review and accept. Licensing review also depends on whether you run the tools as internal CI utilities or ship them inside products. This page does not offer legal advice, so have counsel review the license text and your distribution model before standardizing on either tool.

How is a fixed-scope engagement from DeployOpen agreed before work starts?

Most DeployOpen engagements are fixed-scope, and the scope, deliverables and timelines are agreed in writing before any work begins. A quote follows from that written scope, because DeployOpen does not publish a price list. For a pickle scanning gate, the written scope would typically name the model sources and formats in use, the pipelines to integrate, the allowlist and policy work, the tests and the documentation to be delivered. Ask for the written scope, the deliverables and the acceptance criteria before you commit, and ask whether ongoing upgrades and retesting should be a separate retainer.

How DeployOpen helps choose, implement or migrate a model scanning gate

DeployOpen plans, implements and hardens self-hosted open-source platforms inside the client's own infrastructure, so a model scanning gate can be placed where your model files actually enter your environment. We help teams decide between a byte-signature scanner and a load-time allowlist, then build and document the gate that enforces the choice.

How we scope

  • Written scope names the model formats, repositories and pipelines the gate must cover.
  • We confirm whether checks run before loading, in CI/CD, or at both points.
  • Scope records the license review for ModelScan (Apache-2.0) and Fickling (LGPL-3.0) against your policy.
  • Engagements are fixed-scope, with deliverables and timelines agreed in writing before work starts.

How we build

  • We wire the chosen scanner into your pipeline and fail builds on the severity levels you define.
  • Where a load-time allowlist applies, we place the check in front of torch.load in your inference code.
  • We test the gate against sample files you approve, including deliberately unsafe test files.
  • Every configuration change is kept in version control so reviewers can trace what was enforced.

How we hand over

  • You receive documentation of the scanning points, exit-code handling and known coverage limits.
  • Runbooks explain how to triage findings, quarantine files and record decisions for auditors.
  • We document which controls the gate supports as evidence, without claiming any audit outcome.
  • Handover includes a walkthrough with the engineers who will maintain the scanner after go-live.

How we support

  • Ongoing support, upgrades and continuous testing are available as retainers after handover.
  • We track scanner releases and test upgrades against your pipeline before they reach production.
  • Retainer scope, response expectations and fees are set in a written quote, not estimated here.
  • Ask any provider to confirm how new model formats will be added to the gate and who owns that work.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.