Your teams pull model files from Hugging Face, Kaggle Models, ModelScope and Civitai, and each hub names, versions, hashes and licenses a model in its own way. To scan all of them to one standard, list every source in use, pin each model to an exact version, check every file against the hash the hub publishes (or record your own where it publishes none), and inspect each file statically for unsafe serialization and embedded code before anything loads it. Then rescan on a schedule, because the copy on the hub can change after you approved it.
This guide is for the AppSec lead or ML platform engineer who has just learned that "we only use Hugging Face" stopped being true some time ago. The first two thirds work with whatever tools you already have. Safeguard enters at "How Safeguard does this".
Key takeaways
- A model file is code you did not write. Python's own documentation says pickle data can be built to run arbitrary code while it is being loaded, and PyTorch's
torch.loadwarns never to load data from an untrusted source. - One hub is a review. Several hubs are a program: each has a different version unit, a different hash story, a different licence field and a different credential, so a single intake record has to normalise them.
- Pin every model to an immutable version (a Hugging Face commit, a Kaggle variation version, a ModelScope commit, a Civitai model version), and verify file hashes before load.
- Static inspection reads a file without executing it. It catches unsafe formats and embedded code paths; it does not prove a model is free of backdoors or bias, which OWASP's LLM supply chain entry says plainly.
- Safeguard connects to all four hubs through its Hugging Face, Kaggle Models, ModelScope and Civitai integrations (GA). Each connection is read only, scans the files of the models you select for unsafe serialization formats and embedded code with AI-SPM model file scanning (GA), and records each model in your AI inventory through AI-BOM discovery (GA), with its licence or permissions.
- Rescans run on a schedule under Integrations > Scheduled, or by hand from the project. None of the four integrations uses webhooks.
- Policies and gates (GA) act with Block, Warn and Notify, and approvals run through exceptions.
- Model weights and files are read for the scan and not stored, and the docs for each integration state that no customer data from it is sent to third-party LLMs.
The situation
The ticket usually starts small. A data scientist wants a text-to-image LoRA from Civitai for a marketing prototype. Another team fine-tunes a Gemma variation they found on Kaggle Models. A partner team in another region standardised on ModelScope because that is where their base models live. Meanwhile the main product still pulls a dozen checkpoints from the Hugging Face Hub, some pinned, some tracking main.
Your existing review covers Hugging Face, maybe. It might be a checklist, a scan in CI, or a habit of telling people to prefer safetensors. None of it was written with Kaggle variations, ModelScope commits or Civitai model versions in mind, and nobody has a single list of which models from which hub sit in which project.
A bad week looks like this. A model file loaded in a notebook turns out to be a pickle that imports something it should not. Nobody can say which projects pulled that model, which version they pulled, or whether the copy in the cache matches the copy on the hub. Legal asks whether the Civitai checkpoint allows commercial use, and the answer lives on a web page nobody saved. The fix itself is easy. Finding everything is the slow part.
The goal of this guide is to make that week boring: one intake standard for every hub, one inventory, one rescan rhythm.
Why models from several hubs are harder to secure than one
Every hub hosts the same broad kinds of files (PyTorch checkpoints, safetensors, GGUF, ONNX and framework-specific formats), so the file risk is the same everywhere. What differs is the metadata you need to make a decision and repeat it later. Safeguard's integration docs for each hub describe these differences in detail, and they are worth knowing whether or not you use Safeguard.
| Question | Hugging Face Hub | Kaggle Models | ModelScope | Civitai |
|---|---|---|---|---|
| What identifies a model | Owner and model name, with refs and revisions | Owner, model, framework and variation (for example google/gemma/transformers/2b) | Owner and model name on modelscope.cn | A numeric model id, with numbered model versions |
| What "a version" means | A git revision or commit on a branch or tag | The current version of a variation | The newest commit of the master branch | The newest published model version |
| Does the API publish a file hash | Revisions and file listings are readable through the Hub API | No file hash; the download carries an MD5 or CRC32C from Kaggle's storage | SHA-256 per file in the file list | SHA-256 per file in the version's file list |
| Where licence terms live | Model card and repository metadata | A licence per model version | A licence field per model | No licence id; per-model permissions (commercial use, derivatives, credit), plus the base model's own licence |
| Read credential | User access token, fine-grained recommended | Kaggle API token, or a legacy username:key | SDK token at read level | Personal API key, scoped to the whole account |
| Private or gated content | Private and gated repositories the token can read | Private models of the token's own account; some models require accepting terms first | Private and gated models, after accepting terms | Downloads that need a signed-in account |
Three practical consequences follow.
First, "pin the model" means four different things. On Hugging Face you pin a commit hash. On Kaggle you pin a variation and its version number. On ModelScope you pin a commit, and Safeguard's docs note that ModelScope documents no branch-to-commit lookup, so any tool has to infer the commit from the file list. On Civitai you pin a model version id, not the model id, because the model id points at whatever the newest version is.
Second, hash verification is uneven. ModelScope and Civitai publish a SHA-256 per file, so you can check a download against the hub. Kaggle's API publishes no file hash, so the best you can do is check the size Kaggle lists and the checksum its storage returns, then record your own SHA-256 at the moment of approval and treat that as the reference from then on.
Third, licence answers come in different shapes. A Kaggle or ModelScope licence field gives you an identifier to check. A Civitai model gives you a set of permissions and a base model, and the base model's licence also applies. If your intake form has a single "licence" box, the Civitai answer will not fit in it.
What the rules and references say
This is not legal or audit advice. It is a reading of the primary texts that shape a model intake process, so you can cite them in your own policy.
The format warnings come from the projects themselves
The Python documentation for the pickle module carries a warning box: the module is not secure, and it is possible to construct pickle data that executes arbitrary code during unpickling. It tells readers never to unpickle data that could have come from an untrusted source.
PyTorch's documentation for torch.load repeats the point: it "uses an unpickler under the hood" and you should never load data from an untrusted source. The current signature shows weights_only=True as the default, which restricts what the unpickler will accept. That default helps, but it applies only to code paths that call torch.load directly, and only to the PyTorch version you run.
The Hugging Face Hub documentation on pickle scanning explains why: a pickle can import modules and call builtins as it loads, and constructors run when objects are rebuilt. It suggests loading models from users and organizations you trust, relying on signed commits, or using formats that avoid pickle.
Safetensors was built as the answer to that problem. Its documentation describes it as a simple format for storing tensors safely, as opposed to pickle, and still fast through zero-copy loading. GGUF, documented on the Hub, is a binary format designed for fast loading with GGML-based runtimes, and models trained in PyTorch are often converted to it for local inference.
OWASP names the model supply chain as its own risk
The OWASP Top 10 for LLM Applications 2025 lists Supply Chain as LLM03. Its "Vulnerable Pre-Trained Model" item is the honest framing every model program needs: models are binary black boxes, and OWASP says static inspection "can offer little to security assurances" about hidden behaviour such as backdoors or bias. The same entry calls out licence risk and outdated or deprecated models.
Read that as a scope statement, not a reason to skip scanning. Static inspection is how you catch the file-level problems (unsafe formats, embedded code, tampered files). Behavioural assurance needs evaluation, red teaming and provenance, which are separate jobs.
NIST SP 800-218A extends secure development to AI models
NIST SP 800-218A, published in July 2024 by NIST with a CISA co-author, augments the Secure Software Development Framework (SSDF) version 1.1 with practices, tasks and notes specific to AI model development. If your organisation already maps its development process to the SSDF, 800-218A is where you extend that mapping to the models you train, fine-tune and consume. Third-party models arriving from public hubs fall naturally under the same expectations you apply to third-party code: know where it came from, verify it, and keep a record.
NIST AI RMF frames the risk program around it
The NIST AI Risk Management Framework (AI RMF 1.0) is the US reference for organising AI risk work. NIST's page notes that AI RMF 1.0 is being revised under the White House AI Action Plan, so cite it by version and check for the revision before you quote it in a policy. A model intake process is one of the concrete controls that sits under its governance and mapping functions.
Inventories: SBOM guidance and ML-BOM formats
CISA's SBOM page now leads with the 2026 update to the Minimum Elements for a Software Bill of Materials, which replaces the older 2021 baseline. If a model ships inside your product, your inventory practice should be able to say which model, from where, at which version.
CycloneDX supports a Machine Learning Bill of Materials (ML-BOM), which gives you a standard shape for recording models, datasets and their provenance alongside ordinary components. You do not need to adopt it on day one, but designing your intake record so it maps onto an ML-BOM later saves rework.
Hub-side scanning is helpful and limited
The Hugging Face Hub runs its own scanning on files pushed to repositories, triggered at each commit, and shows badges on files. Read that as a useful signal from one hub, not a control you own. It does not cover the other hubs, it does not know which revision your build pulled, and it does not record anything in your inventory. Several related posts go deeper on what a clean hub badge does and does not mean (see securing Hugging Face models).
Step by step, with or without Safeguard
These steps work with a shell, a spreadsheet and the hubs' own tools. Do them in order; each one depends on the one before.
1. Find every model source in use
You cannot scan what you do not know about. Search code, notebooks, Dockerfiles and CI files for the calls and URLs each hub uses. A starting set of patterns:
# Run from the root of each repository. Adjust the patterns to your code.
rg -n --hidden \
-e 'from_pretrained\(' \
-e 'hf_hub_download|snapshot_download' \
-e 'huggingface\.co/' \
-e 'kagglehub|kaggle\.com/models/' \
-e 'modelscope' \
-e 'civitai\.com/(api|models)' \
.
Then search for model files that are already committed or cached:
find . -type f \( -name '*.bin' -o -name '*.pt' -o -name '*.pth' -o -name '*.ckpt' \
-o -name '*.pkl' -o -name '*.safetensors' -o -name '*.gguf' -o -name '*.onnx' \) \
-not -path './node_modules/*'
Neither command proves absence. They give you a first list to confirm with each team. Our post on finding model files in repos and artifact stores covers caches, buckets and container layers in more depth.
2. Record each model in one intake format
Put every model, from every hub, into the same record. A template that fits all four:
# model-intake.yaml (one entry per model you use)
- name: sentiment-base
hub: huggingface # huggingface | kaggle | modelscope | civitai
locator: OWNER/MODEL # Kaggle: OWNER/MODEL/FRAMEWORK/VARIATION ; Civitai: model id
pinned_version: COMMIT_SHA # HF commit, Kaggle version number, ModelScope commit, Civitai model version id
files:
- path: model.safetensors
sha256: RECORDED_SHA256
hub_published_hash: yes # yes for ModelScope and Civitai; no for Kaggle
format_summary: safetensors # pickle-based | safetensors | gguf | onnx | mixed
licence: apache-2.0 # Civitai: record permissions and base model instead
civitai_permissions: null # commercial_use, derivatives, credit
base_model: null # required for Civitai entries
used_by: [project-a, inference-service]
approved_by: NAME
approved_on: 2026-10-25
rescan: weekly
The fields that matter most are pinned_version, files[].sha256 and used_by. With those three, the bad week above turns into a query.
3. Pin to an immutable version
Use each hub's own version unit:
- Hugging Face. Pass a commit hash as the revision when you download, not a branch name. A branch such as
mainmoves when the owner pushes. - Kaggle Models. Record the full variation path (owner, model, framework, variation) and the version number you approved.
- ModelScope. Record the commit you approved. Because ModelScope documents no branch-to-commit lookup, keep the file list and SHA-256 values with the commit so you can tell later whether a branch still points at the same content.
- Civitai. Record the model version id. The model id alone means "whatever is newest".
4. Verify file hashes before anything loads
Compute a SHA-256 for every downloaded file and compare it with the hub's published value where one exists:
sha256sum model.safetensors
# compare the output with the SHA-256 the hub lists for that file and version
For Kaggle, which publishes no file hash, check the file size Kaggle lists, then record your own SHA-256 at approval. From then on, your recorded hash is the reference, and any later download that differs is a change you did not approve.
5. Inspect files statically, before loading
Static inspection means reading the file's structure without executing it. For pickle-based files, Python ships a disassembler in the standard library that prints the opcodes without running them:
# A plain pickle file
python3 -m pickletools suspicious.pkl | head -50
# A PyTorch .pt or .pth file is usually a zip; list it first, then disassemble the pickle entry
unzip -l model.pt
unzip -p model.pt '*/data.pkl' | python3 -m pickletools - | head -50
What you look for in the output: GLOBAL or STACK_GLOBAL opcodes that import anything beyond the tensor-rebuilding helpers a checkpoint normally needs (torch._utils, collections.OrderedDict, storage types). Imports of os, subprocess, builtins, posix or networking modules in a weights file are a stop sign. This manual check is good for spot reviews; it does not scale to every file in every version from every hub, which is where an automated scanner earns its place.
For safetensors, GGUF and ONNX, the risk profile is different. Safetensors stores a JSON header and raw tensor bytes, with no code path on load. GGUF and ONNX are structured binary formats; check that the file parses as the format it claims to be, and watch for repositories that ship a safetensors file alongside a pickle-based file that your loader might pick first. Our comparison of safetensors, pickle and GGUF has the full table.
6. Prefer safe formats and safe loaders
Where you control the loader, prefer safetensors, and keep weights_only=True on torch.load calls. Where a model only exists as a pickle-based checkpoint, convert it once in an isolated environment with no credentials and no network, record the hash of the converted file, and use that from then on.
| File type you received | Main risk | What to do |
|---|---|---|
Pickle-based checkpoint (.bin, .pt, .pth, .ckpt, .pkl) | Code can run during load | Inspect statically, load only with weights_only=True, convert to safetensors in isolation |
| Safetensors | Low format risk; tampering and licence still matter | Verify hash, record licence, pin version |
| GGUF | Parser bugs in runtimes; tampering | Verify hash, keep the runtime patched, pin version |
| ONNX | Custom operators and runtime bugs | Verify hash, restrict custom ops, keep the runtime patched |
| Repository mixes safe and pickle-based files | Loader may pick the unsafe file | Download only the files you approved; check which file the loader actually opens |
7. Give each hub a least-privilege, read-only credential
Any scanner or mirror you run needs a credential per hub. Keep each one read only and scoped as tightly as the hub allows:
| Hub | Credential | Tightest scope available | Notes |
|---|---|---|---|
| Hugging Face | User access token | Fine-grained, read access to selected repositories or one organization | Hugging Face recommends fine-grained tokens for production; organizations can require approval |
| Kaggle | API token or legacy username:key | No read-only option; create a key for this purpose alone | Revoke when you disconnect |
| ModelScope | SDK token | Read level | Write and admin levels exist; do not use them |
| Civitai | Personal API key | Whole account; no narrower scope | Create a key for this purpose alone; delete it when done |
Rotate each credential on a fixed rhythm. Safeguard's docs recommend at least every 90 days for all four, and note that Hugging Face and Civitai credentials do not expire on their own.
8. Record licence or permissions, per version
Licence terms can change between versions. Record what applied to the version you approved. For Civitai, record the model's permissions (commercial use, derivatives, credit) and the base model, whose own licence also applies. A Civitai LoRA built on a base model with a restrictive licence carries that restriction.
9. Rescan on a schedule and on change
A model you approved last quarter can gain a new version, change its files on a branch you track, or be taken down. Rescan pinned versions on a schedule to confirm nothing changed, and scan new versions before anyone moves to them. Treat a hash mismatch on a pinned version as an incident until you understand it.
10. Decide what blocks and what warns
Write down, before the first finding arrives, which results stop a model from being used and which only raise a flag. A simple starting policy:
| Finding | Action |
|---|---|
| Pickle-based file imports modules outside the tensor-rebuilding set | Block until reviewed |
| File hash differs from the pinned or published value | Block until explained |
| Pickle-based file with only expected imports | Warn; plan conversion to safetensors |
| Licence or permissions unknown, or base model licence unknown | Warn; route to legal |
| Model version no longer available on the hub (archived or taken down) | Notify; plan a replacement |
What to check per hub
Hugging Face Hub: refs, revisions and gated repositories
The Hub is git-backed, so revisions are commits and you can pin exactly. Private and gated repositories need a token that can read them, and organizations can require that tokens be approved by an admin or be fine-grained only. When a scan of a gated model fails with a 403, the cause is almost always the token's scope, its pending approval, or an organization that rejects classic read tokens. For revision pinning in depth, see verifying third-party model files before loading.
Kaggle Models: variations, versions and missing hashes
Kaggle organizes models as owner, model, framework and variation, and versions sit under the variation. Some models require the account to accept the model's terms before downloads work, so a scanner using your key will fail until that account has accepted them. Because the API publishes no file hash, record your own SHA-256 the first time you approve a version.
ModelScope: commits, file lists and pinning
ModelScope publishes a SHA-256 for every file in a model's file list, which makes download verification direct. It documents no branch-to-commit lookup, so pinning works by matching the newest commit named in the file list and confirming that the file list and hashes are unchanged. ModelScope's API also caps how many models per account and files per model it will list; any tool that walks the list needs to say when it hits that cap rather than silently stop. ModelScope also runs its own file check, and a file can be listed before that check finishes.
Civitai: model versions, permissions and mature content
Civitai hosts checkpoints, LoRAs and embeddings, and versions are first-class. It publishes a SHA-256 per file and per-model permissions rather than a licence id. Many Civitai pages carry sample images, some rated mature. A security review needs the files and the permissions, not the images, and a scanner that fetches only text and model files keeps image content out of your tooling entirely. Civitai can also archive or take down a model, after which its files are no longer served.
How Safeguard does this
Safeguard connects to the Hugging Face Hub, Kaggle Models, ModelScope and Civitai through four integration cards (GA). Every one of them is read only, scans the files of the models you select with AI-SPM model file scanning (GA), and records each model in your AI inventory through AI-BOM discovery (GA). The flow below is built from Safeguard's integration docs for each card.
-
Open Integrations and find the card. The Hugging Face card sits under Integrations on the Project/Product tab. The Kaggle Models, ModelScope and Civitai cards sit under Integrations in the AI models group. The docs note that these three are switched on per workspace; if you do not see a card, ask your Safeguard contact to enable it.
-
Choose Public or Private. Each card offers two modes. Public takes a model URL and needs no credential. Private takes a Name and a credential, and lists what that credential can read.
Hub Public: what you paste Private: what you paste Private: what you can select Hugging Face A model URL on huggingface.co A user access token (fine-grained recommended) Your models and your organizations' models, plus any added by URL, including private and gated models the token can read Kaggle Models A model variation URL on kaggle.com/models A Kaggle API token, or a legacy username:keyEvery variation of your account's models, private ones included, plus any added by URL ModelScope A model URL on modelscope.cn An SDK token (read level is enough) Your account's models, private and gated included, plus any added by URL Civitai A model URL on civitai.com A personal API key Every model your account published, plus any added by URL, including downloads that need a signed-in account -
Create the credential with the least access the hub allows. The docs walk through each one:
- Hugging Face: Settings > Access Tokens > New token, choose Fine-grained, name it, and grant read access to the repositories or organization to scan. Add read access to gated repositories only if you need them. The token starts with
hf_. - Kaggle: Settings from your profile picture, then create an API token under API (or a legacy key, which downloads
kaggle.json; join its username and key asusername:key). - ModelScope: open your account's Access Token page and create a token with read access.
- Civitai: Account settings, then API Keys, add a key named Safeguard, and copy it (Civitai shows it once).
- Hugging Face: Settings > Access Tokens > New token, choose Fine-grained, name it, and grant read access to the repositories or organization to scan. Add read access to gated repositories only if you need them. The token starts with
-
Optionally check the credential first with the hub's own tool. The docs give these checks, which run against the hub, not against Safeguard. We have not run them for this post; they are reproduced as the docs show them.
# Hugging Face (the Hugging Face CLI has no command that creates a token) hf auth login --token "$HF_TOKEN" hf auth whoami # Kaggle export KAGGLE_API_TOKEN="<your token>" kaggle models list --owner "<your username>" # ModelScope modelscope login --token "$MODELSCOPE_API_TOKEN" # Civitai curl -H "Authorization: Bearer $CIVITAI_TOKEN" https://civitai.com/api/v1/me -
Connect and select. For Public, enter a Name, paste the URL, click Add, then Next. For Private, enter a Name, paste the credential into Access Token and verify it. Then click Next, select the models (Hugging Face models and revisions, Kaggle variations, ModelScope models, Civitai models), review and connect.
-
Safeguard downloads and checks each file, then scans it. What happens per hub, as the docs describe it:
- Hugging Face. Safeguard reads refs and revisions, downloads the files of each selected model at the selected revision, and scans them for issues such as unsafe serialization formats and embedded code.
- Kaggle Models. Each variation is scanned at its current version. Because Kaggle's API publishes no file hash, Safeguard checks each file against the size Kaggle lists and the MD5 (or CRC32C) that Kaggle's storage returns with the download, and records the file's SHA-256.
- ModelScope. Each model is scanned at the newest commit of its master branch. Safeguard checks each file against the SHA-256 ModelScope publishes. A branch is pinned to the newest commit its file list names, and only when that commit lists the same files with the same SHA-256.
- Civitai. Each model is scanned at its newest published version, and each file is checked against the SHA-256 Civitai publishes.
On every hub, the scan itself is static: AI-SPM reads the model files and looks for unsafe serialization formats and embedded code. It does not execute the model.
-
Each model lands in the AI inventory, with its terms. The scan results and an AI inventory entry are stored per model. Kaggle and ModelScope entries carry the model's licence. Civitai entries carry the model's own permissions as Civitai publishes them (commercial uses allowed, derivatives, credit) and name the base model, whose own licence also applies, because Civitai publishes no licence id.
-
Civitai stays text only. Safeguard reads text only from Civitai. No Civitai image or avatar is fetched or shown, and a model Civitai rates as mature is listed as text with a "mature content (text only)" marker. That keeps image content out of your security tooling without hiding the model from your inventory.
-
Rescan on a schedule or by hand. None of the four integrations uses webhooks. Each selected model is scanned when you connect it. To pick up new revisions, versions or commits, set a schedule under Integrations > Scheduled, or rescan by hand from the project.
-
Act on results with policies and gates. Policies and gates (GA) are where Safeguard enforces decisions, with three actions: Block, Warn and Notify. Approval for anything a gate stops runs through exceptions, so a team that needs something through can request it and leave a record. The integration docs for these four hubs describe scanning and inventory, not gate wiring, so check how model scan findings show up in your policy screens before you rely on a Block, and use the decision table from step 10 above as the starting rule set.
-
Rotate and disconnect cleanly. To rotate, create or refresh the credential on the hub, find the connection under Project Configurations, choose Update, paste the new credential and save, then delete the old one on the hub. To disconnect, choose Delete from the connection's menu under Project Configurations, confirm, then delete or revoke the credential on the hub.
What Safeguard reads and stores
| Read | Stored | Not stored | |
|---|---|---|---|
| Hugging Face | Account name, model names, refs and revisions, files of selected models | Connection settings, scan results, AI inventory entries, the token (encrypted at rest, never shown again) | Model weights |
| Kaggle Models | Username, models and variations, each version's licence and file list, files of selected variations | Connection settings, scan results, AI inventory entries, the token (encrypted at rest) | Model files, which are read for the scan and removed |
| ModelScope | Username, model names, licences and visibility, each file list with SHA-256, files of selected models | Connection settings, scan results, AI inventory entries, the token (encrypted at rest) | Model files, read for the scan and removed |
| Civitai | Username, model names, types, base models, ratings and permissions, each version's file list with SHA-256, files of selected models | Connection settings, scan results, AI inventory entries, the key (encrypted at rest) | Model files, and anything from Civitai's images |
The docs for each of the four integrations also state that no customer data from it is sent to third-party LLMs.
What each integration never needs
The docs list the access Safeguard never asks for, which is useful when your identity team reviews the request:
- Hugging Face: write access, inference or billing permissions, organization admin rights, or access to datasets and Spaces.
- Kaggle: write access, competition or dataset publishing rights, or another person's credentials.
- ModelScope: write or admin access, Studio or deployment access, or another person's token.
- Civitai: Buzz or generation access, or the right to post, comment or upload. Civitai OAuth app credentials do not work; Safeguard uses a personal API key.
Troubleshooting the common failures
| What you see | Hub | Likely cause | Fix |
|---|---|---|---|
| A gated or organization model fails with 403 | Hugging Face | Token lacks read access, is pending approval, or the org requires fine-grained tokens | Grant read access, wait for approval, or use a fine-grained token |
| Model is private. Authentication required. | Hugging Face | Private model added on the Public tab | Use the Private tab with a token |
| A scan fails with a gated or 403 error | Kaggle | The model's licence has not been accepted on Kaggle | Accept the terms with the token's account, then rescan |
| This is not a Kaggle model URL | Kaggle | URL is not a model variation page | Use the full owner, model, framework and variation URL |
| A scan says ModelScope is still checking a file | ModelScope | ModelScope's own file check is not finished | Rescan later |
| A scan fails with a file hash mismatch | ModelScope, Civitai | The download did not match the published SHA-256 | Rescan; if it repeats on ModelScope the model changed mid-download, on Civitai report the model to Civitai |
| Civitai has archived this model (or taken it down) | Civitai | Civitai moderated the model and no longer serves its files | Nothing to scan; remove it from the connection |
What Safeguard does not do
- It does not prove a model is safe to use. AI-SPM model file scanning is static. It reads files and flags unsafe serialization formats and embedded code; it does not run the model, and it cannot detect backdoors, poisoned training data, bias or harmful outputs. OWASP is clear that static inspection offers little assurance about those. Evaluation and red teaming remain your job.
- It does not write to any hub. Every integration is read only. It will not open a discussion, file a report, push a fix, edit a model card or convert a checkpoint for you. Reporting a bad model to the hub, and converting pickle-based files to safetensors, stay with your team.
- It does not watch hubs in real time. None of the four integrations uses webhooks. New versions are picked up when a scheduled rescan runs or when someone rescans by hand. Set a schedule that matches how fast your teams adopt new versions.
- It does not scan Hugging Face datasets or Spaces through this card, and it does not need access to them. If your risk includes datasets or Spaces, handle them separately.
- It does not see models it is not told about. A model downloaded in a notebook from a hub URL nobody added to a connection is not in the inventory. Step 1 of this guide (finding every source) still matters.
- It does not decide licence questions. It records the licence, or on Civitai the permissions and base model, as the hub publishes them. Whether a use is allowed is a legal decision.
- It does not narrow credentials the hub cannot narrow. Kaggle offers no read-only key and Civitai keys cover the whole account. Safeguard only reads, but the key you hand over can do more; create one for this purpose alone and revoke it when you disconnect.
- It does not lift hub-side limits. ModelScope's API caps how many models and files it lists; past that cap Safeguard says so rather than cutting the list silently, and you add the rest by URL.
Common mistakes
- Pinning the model, not the version. A Civitai model id, a Kaggle model without a variation version, or a Hugging Face
mainbranch all move. Pin the version unit each hub uses. - Treating a hub badge as your control. A clean badge on one hub says nothing about the other hubs, the revision your build pulled, or the copy in your cache.
- Scanning once at intake and never again. Files under a tracked branch can change. Pinned versions can be taken down. Schedule rescans.
- Using a write token "because it was there". Every hub here works with read access, and Kaggle and Civitai keys already reach further than you would like. Do not add write scope on top.
- One licence box for every hub. Civitai permissions and base model licences do not fit a single licence id. Record both.
- Converting checkpoints on a developer laptop. Converting a pickle-based file means loading it. Do it in an isolated, credential-free environment, then pin the converted file's hash.
- Forgetting the loader. A repository with both a safetensors file and a pickle-based file may load the pickle if your code asks for it. Check which file is actually opened.
- Letting the inventory drift from the code. If a project stops using a model, remove it from the connection. If a new one appears, add it before it ships.
FAQ
How do I scan a Hugging Face model before downloading it?
Pin a commit, list its files, and scan those files in an environment where nothing loads them. With Safeguard, add the model URL on the Hugging Face card's Public tab, or connect a fine-grained read token on the Private tab, select the model and revision, and connect. Safeguard downloads and scans the files and records the model in your AI inventory.
Can Safeguard scan Kaggle Models?
Yes. The Kaggle Models integration (GA) scans each selected model variation at its current version and records it with its licence. It works with a Kaggle API token or a legacy username:key, and public variations can be added by URL with no credential. The card is switched on per workspace.
Does Safeguard support ModelScope?
Yes. The ModelScope integration (GA) scans each model at the newest commit of its master branch, checks every file against the SHA-256 ModelScope publishes, and records the model and its licence in your AI inventory. A read-level SDK token is all it needs for private models.
Can I scan Civitai checkpoints and LoRAs without pulling images into my tools?
Yes. The Civitai integration reads text only. No Civitai image or avatar is fetched or shown, and models Civitai rates as mature appear as text with a "mature content (text only)" marker. Model files are checked against Civitai's SHA-256 and scanned, then removed.
Is a safetensors file always safe to load?
The format has no code path on load, which removes the main pickle risk. It does not tell you whether the weights were tampered with, whether the licence allows your use, or whether the repository also ships a pickle-based file your loader might pick. Verify the hash and the file your code actually opens.
Does Hugging Face's own scanning mean I can skip mine?
No. Hub-side scanning is a useful signal for one hub at the time of each commit. It does not cover Kaggle, ModelScope or Civitai, does not know which revision your build pulled, and does not maintain your inventory.
How often should I rescan models from public hubs?
Match your adoption rate. If teams move to new versions weekly, rescan weekly. In Safeguard, set a schedule under Integrations > Scheduled, or rescan by hand from the project; there are no webhooks.
Does Safeguard store our model weights?
No. Model files are read for the scan and not kept. Safeguard stores the connection settings, the scan results, the AI inventory entry for each scanned model and the credential, which is encrypted at rest and never shown again.
What permissions does the Hugging Face token need?
Read access to the repositories or organization you want scanned, ideally as a fine-grained token. Add read access to public gated repositories only if you need them. Safeguard never needs write, inference, billing, webhook or discussion permissions.
Is model file scanning enough for an AI supply chain program?
No. It covers the file layer. You still need inventory of where models are used, version pinning, licence review, evaluation of model behaviour, and patching of the libraries and runtimes that load models.
Model files are one layer of the AI supply chain; the Python frameworks, tokenizers and serving runtimes that load them are ordinary open source dependencies with ordinary CVEs. The section below covers how Safeguard closes the fix gap for those dependencies and the container images you build around your models.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation categories include dependencies, licenses, security posture and findings, and each one is set separately. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds.
3. Gold Registry: start from components that are already fixed
Gold Registry provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs and a completed license check, with signed build provenance (signed with Safeguard's key and verifiable with cosign, SLSA Build Level 3 as the design target) and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. Ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | Safeguard policies and gates in CI |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
None of these demos shows the model hub integrations themselves. They show the surfaces your team would use around them: asking questions of your Safeguard data from Claude, fixing a vulnerable dependency from the terminal, and scanning from your own machine.
The first demo connects Claude to the Safeguard MCP server (GA) with OAuth and shows how you choose which tools Claude can use. Once your model scans and inventory are in Safeguard, the same connection is how an engineer can ask about findings from inside Claude.
Click through it at your own pace, or open it full screen.
The second demo is a real session with the Safeguard CLI (GA). It installs the CLI, opens the interactive terminal with safeguard, and asks it to fix the lodash CVE in a repository. The CLI reads the finding and advisory, asks before any command that changes something, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, prints a summary and pushes nothing. The same loop applies to the Python libraries that load your models.
Click through it at your own pace, or open it full screen.
The third demo sets up the local runner (GA) on your own machine, approves it with its device code, and scans from the terminal. Teams that keep model code and conversion scripts on internal machines can scan that code without moving it.
Click through it at your own pace, or open it full screen.
Quick check
Why can a Kaggle model not be verified against a hub-published hash the way a ModelScope or Civitai model can?
Kaggle's API publishes no file hash. The best available check is the file size Kaggle lists plus the checksum its storage returns with the download, after which you record your own SHA-256 as the reference. Safeguard does exactly that and records the SHA-256 of each file.
A Civitai LoRA allows commercial use. Is that the whole licence answer?
No. Civitai publishes per-model permissions rather than a licence id, and the base model the LoRA was built on has its own licence, which also applies. Record both.
Sources
- Safeguard docs: Integrations overview
- Safeguard docs: Hugging Face integration
- Safeguard docs: Kaggle Models integration
- Safeguard docs: ModelScope integration
- Safeguard docs: Civitai integration
- Python documentation: pickle module
- PyTorch documentation: torch.load
- Hugging Face Hub docs: Pickle scanning
- Hugging Face Hub docs: file scanning on the Hub
- Hugging Face Hub docs: User access tokens
- Hugging Face docs: Safetensors
- Safetensors project repository
- Hugging Face Hub docs: GGUF
- OWASP Top 10 for LLM Applications 2025: LLM03 Supply Chain
- NIST SP 800-218A: Secure Software Development Practices for Generative AI and Dual-Use Foundation Models, an SSDF Community Profile
- NIST AI Risk Management Framework
- CISA: Software Bill of Materials
- CycloneDX: Machine Learning Bill of Materials
Related reading: securing Hugging Face models, verifying third-party model files before loading, finding model files in repos and artifact stores, safetensors vs pickle vs GGUF and AI-SPM, AI Gateway and AI-BOM.
To try it, download Safeguard at safeguard.sh/download and read the setup guides at docs.safeguard.sh/docs.
Last reviewed: 25 October 2026. Product capabilities change; check docs.safeguard.sh for the current state.