You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently anomalib engine loads checkpoints using weights_only=False. This will end up executing malicious coded if the checkpoint comes from untrusted sources. This PR proposes changes to AnomalibModule to mitigate this.
An alternative to this design is to use TRUST_REMOTE_CODE=True but this might make the users set this is their default env variable which is risky.
Design
This design introduces a scoped allowlist used at both checkpoint load seams:
Shared first-party enums (ANOMALIB_SAFE_GLOBALS)
Shared numpy leaf types (NUMPY_SAFE_GLOBALS)
Optional per-model extras via AnomalibModule.checkpoint_safe_globals()
withanomalib_safe_globals(extra=cls.checkpoint_safe_globals()):
torch.load(..., weights_only=True) # via Lightning / CheckpointIO
Rules for what may be added:
Shared anomalib list: first-party enums reused across models.
Numpy list: inert reconstruction helpers / dtypes required for scheduler and
optimizer state under NumPy 2.x (numpy._core). Both numpy.core and numpy._core pickle path aliases are registered so older pickles still resolve.
The project’s dependency floor is NumPy ≥ 2 (via opencv-python-headless), so
importing numpy._core.multiarray is intentional.
Model extras: small first-party types persisted only by that model’s
constructor hyperparameters. Not shared third-party types, not modules, not pathlib.Path.
Dual load seams
Checkpoint restore happens in two places; both must use the same allowlist policy.
Direct API / export:AnomalibModule.load_from_checkpoint wraps Lightning’s
loader with extra=cls.checkpoint_safe_globals().
Trainer ckpt_path:AnomalibCheckpointIO wraps TorchCheckpointIO. The
Engine installs it when the user has not supplied a CheckpointIO, and refreshes extra_safe_globals from the active model before fit / validate / test / predict.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The security goal is not reliably enforced yet (weights_only defaults still defer to upstream defaults), and there are import/compatibility and repo-header convention issues that should be addressed before approval.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This PR hardens anomalib checkpoint loading by introducing a scoped allowlist mechanism intended to support torch.load(..., weights_only=True) without executing arbitrary code from untrusted checkpoints, applying the policy both to direct AnomalibModule.load_from_checkpoint usage and Trainer ckpt_path restores via a custom CheckpointIO plugin.
Changes:
Added anomalib_safe_globals context manager plus shared allowlists for first-party enums and NumPy leaf types used during optimizer/scheduler state restore.
Added an AnomalibCheckpointIO plugin and Engine wiring to ensure Trainer restores use the same allowlist policy.
Added per-model checkpoint_safe_globals() overrides for models that persist model-local enums in hyper_parameters.
File summaries
File
Description
src/anomalib/utils/serialization.py
New safe-globals allowlist/context manager used to constrain checkpoint unpickling under weights_only.
The reason will be displayed to describe this comment to others. Learn more.
Minor comments.
Can you also make sure tiling checkpoints are also loaded okay with this this new changes. get_ensemble_model() Tiling loading passes a preprocessor and i feel this might fail
Some files might need year update in copyright headers.
Do we need a similar weight_only plugin for TorchInferencer as well ? It still uses torch.load(path, map_location=self.device, weights_only=False) # nosec B614
The reason will be displayed to describe this comment to others. Learn more.
similar to the copilot's comment.
I think it might be better to explicitly enforce weights_only=True by default
here and in
anomalib/src/anomalib/models/components/base/anomalib_module.py
Lightning might change None to False for HTTP/HTTPS checkpoint URLS?
The new tests exercise AnomalibCheckpointIO.load_checkpoint and plugin installation directly, but none drives Lightning's fit/validate/test/predict with ckpt_path through these changed Engine calls. Add one deterministic Engine-level restore test to catch plugin wiring or positional-argument regressions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📝 Description
weights_only=False. This will end up executing malicious coded if the checkpoint comes from untrusted sources. This PR proposes changes toAnomalibModuleto mitigate this.TRUST_REMOTE_CODE=Truebut this might make the users set this is their default env variable which is risky.Design
This design introduces a scoped allowlist used at both checkpoint load seams:
ANOMALIB_SAFE_GLOBALS)NUMPY_SAFE_GLOBALS)AnomalibModule.checkpoint_safe_globals()In Anomalib Module
Override
Introduce
Model specific globals live here.
Add new plugin for model checkpoint
AnomalibCheckpointIOSingle context manager, layered allowlist
anomalib.utils.serialization.anomalib_safe_globalsmerges three layers for the duration of a load:
Rules for what may be added:
optimizer state under NumPy 2.x (
numpy._core). Bothnumpy.coreandnumpy._corepickle path aliases are registered so older pickles still resolve.The project’s dependency floor is NumPy ≥ 2 (via
opencv-python-headless), soimporting
numpy._core.multiarrayis intentional.constructor hyperparameters. Not shared third-party types, not modules, not
pathlib.Path.Dual load seams
Checkpoint restore happens in two places; both must use the same allowlist policy.
AnomalibModule.load_from_checkpointwraps Lightning’sloader with
extra=cls.checkpoint_safe_globals().ckpt_path:AnomalibCheckpointIOwrapsTorchCheckpointIO. TheEngine installs it when the user has not supplied a
CheckpointIO, and refreshesextra_safe_globalsfrom the active model before fit / validate / test / predict.Caller code stays unchanged:
Per-model extension point
✨ Changes
Select what type of change your PR is:
✅ Checklist
Before you submit your pull request, please make sure you have completed the following steps:
For more information about code review checklists, see the Code Review Checklist.