Modelscanning
En modelfil kan køre kode, når den indlæses. Et PyTorch-checkpoint er en Python-pickle,
og når den unpickles, kan den importere og kalde hvad som helst. Keras-Lambda-lag,
GGUF-chatskabeloner og brugerdefinerede ONNX-operatorer er andre veje ind. fremforge
scanner modelfiler, uanset hvor de lander i din organisation, og gemmer én dom pr. fil.
Din organisations politik afgør, hvad der sker med en fil, som scanningen finder noget i.
Ingen model bliver nogensinde indlæst eller kørt for at blive scannet. Scanneren læser filens struktur: pickle-filens importliste, safetensors- og GGUF-headerne, ONNX-grafen og Keras-konfigurationen.
Hvor modelfiler findes
| Overflade | Hvornår den scannes | Hvad håndhævelse gør |
|---|---|---|
| Git LFS | Ved upload | Afviser uploaden med 422 |
| Pakker (generiske og alle typer, hvor uploadens body er selve filen) | Ved upload | Afviser uploaden med 422 |
Container-registry (ModelPack, KitOps, Docker ai/ og modelfiler i almindelige images) | Efter pushet | Afviser et pull, der ville levere laget, med 403 |
| Afhængighedsproxy (container-images) | Første gang den hentes | Afviser senere pulls af laget med 403 |
| Actions-artefakter | Når kørslen er færdig | Intet. Artefakter får kun fund |
En fil genkendes som en model på sine første bytes, ikke på sit navn. En pickle, der
er gemt som weights.txt, bliver stadig fundet.
Formater og domme
| Format | Hvad kontrolleres |
|---|---|
Pickle, joblib, PyTorch (.pt, .pth, .bin, ældre format og zip), NumPy-objektarrays | Hver import i pickle-filen mod en tilladelsesliste. Tilladelseslisten er det, PyTorchs torch.load(weights_only=True) accepterer, plus de NumPy-typer, et state dict har brug for |
| safetensors | Headeren: længder, datatyper og offsets, og at filen ikke også kan åbnes som zip eller pickle |
| GGUF | Metadata, chatskabelonen (mod en sikker delmængde af Jinja) og de samme zip- og pickle-kontroller |
| ONNX | Domæner for brugerdefinerede operatorer og stier til eksterne data, der peger uden for modellens mappe |
Keras (.keras, .h5) | Lambda-lag og brugerdefinerede objekter uden for Keras-navnerummet |
Hver fil får én dom, som deles af alle organisationer, der har de samme bytes:
- Ren: intet fundet.
- Mistænkelig: en import uden for tilladelseslisten (
pickle-unknown-import), en klasse fra et kendt ML-framework (pickle-framework-object, se Framework-pickles), en GGUF-skabelonkonstruktion uden for den sikre delmængde, en brugerdefineret ONNX-operator eller en fil, der også kan åbnes som et andet format. - Ondsindet: en import på scannerens blokeringsliste (som
os.systemellerbuiltins.eval) eller et Keras-Lambda-lag. - Kan ikke scannes: filen kunne ikke læses til ende: en ødelagt zip, et 7z-arkiv, en afkortet strøm.
- Formatverificeret: en safetensors- eller GGUF-fil over 4 GiB, hvis strukturkontrol bestod. Se Over 4 GiB.
Scanneren er open source: picklescan til gennemgangen af pickle-filer, med fremforges tilladelsesliste ovenpå.
Din organisations politik
Politikken har tre tilstande. Sæt den under Sikkerhed › Politikker › Modelscanning eller med API’et.
| Tilstand | Hvad sker der |
|---|---|
| Skygge (standard) | Hver fil scannes, og de filer, politikken ville blokere, vises som fund. Intet afvises. |
| Håndhæv | Som skygge, og filer med et åbent fund afvises som beskrevet i Hvor modelfiler findes. |
| Fra | Filer scannes stadig, og fundene vises stadig, men intet afvises eller tælles som ville-være-blokeret. |
Ved håndhævelse blokerer politikken en fil, hvis dom er Ondsindet, Kan ikke scannes eller Mistænkelig, medmindre fundet er afvist. En fil, der er Ren eller Formatverificeret, går altid igennem.
Sådan ser håndhævelse ud
En upload, der afvises, svarer 422 med dommen, fundkoderne og filens sha256:
{
"error": "model file rejected",
"rule": "suspicious",
"verdict": "suspicious",
"findings": ["pickle-unknown-import"],
"sha256": "d24ec017bdcf45a8737b4a9398e6eea64fa37a5821f473041cb3bc03f8489687"
}En fil, der ikke er scannet før, scannes under uploaden. Det tager højst et par sekunder ekstra for en fil på op til 256 MiB. En safetensors- eller GGUF-fil over 256 MiB kontrolleres på sin header og sine sidste 64 KiB. Andre modelfiler over 256 MiB accepteres og scannes lige efter uploaden, så de dukker op som et fund et minut senere i stedet for at blive afvist.
Kan scanneren ikke nås, svarer en upload af en modelfil i en organisation, der
håndhæver, 503 med Retry-After: 30. Uploads af andre filer påvirkes ikke.
Et container-pull, der ville levere et blokeret lag, svarer 403 DENIED med
årsagen model-malicious, model-suspicious eller model-unscannable og lagets
digest. Et modellag, du lige har pushet, scannes inden for cirka et minut. Indtil da
svarer et pull 403 med årsagen model-scan-pending, på samme måde som et image med
et lag, der stadig malwarescannes. Pulls fra runners hostet af fremforge holdes ikke
tilbage af en ventende scanning.
Uploading failed due to unsupported Content-Type header(s), og
git lfs push --object-id afslutter med 0. Et almindeligt git push fejler. Årsagen
står i svarets body, og filen vises som et fund under Modelscanning.Framework-pickles
Nogle checkpoints gemmer hele Python-objekter, ikke kun vægte: en YOLO-model, en
TrainingArguments-fil, en scikit-learn-pipeline. Når en af dem indlæses, kører den
pågældende klasses kode. Scanneren mærker dem pickle-framework-object, når alle
importer uden for vægt-tilladelseslisten kommer fra et kendt framework:
PyTorch-moduler, Transformers, Ultralytics, scikit-learn, joblib, timm, Lightning,
SpeechBrain eller Diffusers.
De er Mistænkelig som enhver anden ukendt import. For at lade dem passere
håndhævelse skal du slå Tillad pickles fra kendte ML-frameworks
(allow_framework_pickles) til. En fil med et hvilket som helst andet fund blokeres
stadig.
Afvisning af et fund
En ejer af organisationen kan afvise et fund for én fil (én sha256) med en begrundelse og en udløbsdato: 90 dage som standard, højst 365. En afvist fil går igennem håndhævelse og forsvinder fra listen over fund. Afvisninger gælder pr. organisation; en anden organisation med de samme bytes påvirkes ikke. En afvisning kan til enhver tid tilbagekaldes.
Over 4 GiB
Malwarescanneren, ClamAV, kan ikke læse mere end 4 GiB af én fil, og fremforge afviser en fil, den ikke kan scanne. For modelvægte, som ofte er større end 4 GiB, er der én undtagelse i alle tilstande: en safetensors- eller GGUF-fil, hvis strukturkontrol består, accepteres som Formatverificeret. Disse formater indeholder kun tensorer og metadata, og strukturkontrollen beviser, at filen ikke indeholder andet. Filen malwarescannes ikke.
Alle andre filer over 4 GiB, herunder alle pickles, afvises stadig. Grænsen for én fil er 10 GiB. Store modeller udgives som shards på 5 GB eller mindre, så det er sjældent denne grænse, der betyder noget.
Actions-artefakter
Når en workflow-kørsel er færdig, kontrolleres de filer, den uploadede med
actions/upload-artifact, for modelfiler, og de scannes. Et fund vises under
Modelscanning med repositoriet, kørselsnummeret og artefaktet. Artefakter afvises
eller slettes aldrig: at blokere en upload ville få dit workflow til at fejle uden
mulighed for at tilsidesætte det.
AI-beholdning
Sikkerhed › Komponenter › AI-beholdning viser de maskinlæringsmodeller, din organisation har, og dem, dens CI henter. Siden er skrivebeskyttet; politikken og afvisningerne ligger stadig på siden for modelscanning.
Modelfiler
Én række pr. modelfil (pr. sha256) fundet i dit Git LFS, dine pakker, container-images, pulls gennem afhængighedsproxyen og Actions-artefakter, med:
- dens format og størrelse og dens dom (Venter på scanning, mens den venter på at blive scannet);
- dens licens, som den er angivet (se Hvor licenser kommer fra), og hvor den blev angivet. En model uden angivet licens vises som Ukendt. fremforge gætter ikke en licens ud fra et filnavn;
- hvad dens header oplyser: antal parametre, tensor-datatyper og for GGUF arkitekturen og modelnavnet;
- hvor den forekommer: hvert repository, hver pakke, hvert image eller artefakt, den er set i.
Hver modelfil findes også i komponentbeholdningen
som pkg:generic/<file name>@<sha256>, så en komponentsøgning finder den, og
“hvor bruges den” også virker for modeller. En model, som din CI henter fra Hugging
Face, står der som pkg:huggingface/<org>/<name>@<revision> ved det repository, hvis
workflow henter den.
Hvor licenser kommer fra
fremforge læser kun en licens fra metadata, der allerede er gemt på fremforge, og spørger ingen andre: intet om dine modeller forlader platformen. I denne rækkefølge:
- Selve filen: GGUF
general.licenseeller en licensnøgle i en safetensors-fils metadata. - Det modelartefakt, filen er et lag i, når du pusher det til din organisations
registry eller henter det gennem
afhængighedsproxyen. fremforge læser
artefaktets små metadata-blobs fra sit eget lager, aldrig vægtene og aldrig
upstream-registryet:
Pakning Læses ModelPack ( modctl)konfigurationens descriptor.licensesKitOps ( kit)Kitfile: en modeldels licensefor den del, dereftermodel.license, derefterpackage.licenseDocker Model Runner ( docker model,ai/…)GGUF general.licensei modelkonfigurationen, ellers licensfilen i artefaktet (application/vnd.docker.ai.license): Apache-2.0 og MIT genkendes på deres tekst, andre licenser på deres titel, såsomLLAMA 3.2 COMMUNITY LICENSE AGREEMENTenhver af dem manifest-annotationen org.opencontainers.image.licenses
API’et returnerer, hvor hver licens blev angivet, som licence_from, for eksempel
ModelPack config descriptor.licenses; AI-beholdningen viser det ved siden af
licensen. En licens fra et image, du har pushet, vises kun for din organisation. En
model, der er hentet før 13. oktober 2026, får sin licens fra artefaktet inden for en
time, hvis artefaktet stadig er gemt.
Modeller, din CI henter
Den daglige workflow-scanning læser hvert workflow på hvert repositorys
standardbranch og de Python- og shellscripts, et workflow kører fra det samme
repository (python scripts/fetch.py, bash ci/prepare.sh). Den finder:
| Værktøj | Findes som |
|---|---|
| Hugging Face | from_pretrained("org/name"), hf_hub_download(repo_id=…), snapshot_download(…), huggingface-cli download, hf download |
| Ollama | ollama pull name:tag |
| Docker | docker model pull ref |
| KitOps | kit pull ref |
| ModelPack | modctl pull ref |
En reference er fastlåst, når den ikke kan ændre sig under dit build: en Hugging
Face-model med en fuld commit-sha på 40 tegn som revision
(revision="<sha>" eller --revision <sha>), og en Ollama-, Docker-, KitOps- eller
ModelPack-model med et @sha256:-digest. En branch eller et tag som main eller
v1.0 er ikke fastlåst. Hver ikke-fastlåst reference er et fund, ligesom en action,
der er fastlåst til et tag i stedet for et commit.
Et modelnavn, der ikke står i filen, såsom from_pretrained(model_name), vises som
Navn sat ved kørsel. Et HF_ENDPOINT, der er sat i samme fil, vises, fordi pullet
så går til det endpoint i stedet for huggingface.co. En reference, du fjerner,
forsvinder inden for tre dage.
Findes ikke: oras pull (et ORAS-artefakt er kun en model i kraft af sin medietype,
som kommandoen ikke viser; hentet gennem afhængighedsproxyen klassificeres det ud fra
sit manifest) og Python-kode uden for de scripts, et workflow kører.
Licensen for en Hugging Face-model, som din CI henter ved navn, vises som Ukendt: fremforge kontakter ikke Hugging Face eller nogen anden for at slå den op. En model, som din CI henter som et OCI-artefakt gennem afhængighedsproxyen, får sin licens fra artefaktet (se Hvor licenser kommer fra).
ML-BOM
Download ML-BOM (CycloneDX) på siden eller GET /ai/ml-bom returnerer
beholdningen som et CycloneDX 1.6-dokument. Hver modelfil er en komponent af typen
machine-learning-model med sin sha256, sin angivne licens (hvor den blev angivet, er
egenskaben fremforge:model:licence_from), sin arkitektur som
modelCard.modelParameters.modelArchitecture, når headeren navngiver en, og sit format,
sin dom, sine overflader, sin størrelse, sit antal parametre og sine datatyper som
fremforge:model:*-egenskaber. Kun fakta, der er læst fra filen, angives.
De SBOM’er, din CI uploader, ændres ikke: de er dine filer. ML-BOM’en er et separat dokument.
Compliance-rapport
Compliance-rapporten har et afsnit om AI-beholdning: antallet af modelfiler, de filer, din politik blokerer eller ville blokere, filer med et afvist fund, din tilstand for modelscanning, CI-modelpulls uden en fast revision og filerne pr. angivet licens. Dens CSV viser alle modelfiler. Afsnittet dækker altid hele organisationen, også i en rapport for ét repository.
Revisionslog
| Hændelse | Hvornår |
|---|---|
security_policy.model_scan.updated | Tilstanden eller indstillingen for framework-pickles blev ændret |
security_policy.model_scan.dismissed | Et fund blev afvist, eller en afvisning blev fornyet |
security_policy.model_scan.dismissal_revoked | En afvisning blev tilbagekaldt |
registry.pull.blocked med gate: model | Et pull blev afvist af modelpolitikken |
En afvist pakkeupload eller et afvist container-pull står også i
registry-adgangsloggen med årsagen model_policy:<rule>.
Adgangsloggen dækker ikke Git LFS.
API
| Kald | Scope |
|---|---|
GET /_app/api/v1/orgs/{org}/security/model-policy | policy:read |
PUT /_app/api/v1/orgs/{org}/security/model-policy | policy:write |
GET /_app/api/v1/orgs/{org}/security/model-findings?status=open|dismissed|all | findings:read |
POST /_app/api/v1/orgs/{org}/security/model-findings/{sha256}/dismiss | policy:write |
DELETE /_app/api/v1/orgs/{org}/security/model-findings/{sha256}/dismissal | policy:write |
GET /_app/api/v1/orgs/{org}/ai/models?verdict=&format=&licence=&surface= | components:read |
GET /_app/api/v1/orgs/{org}/ai/models/{sha256} | components:read |
GET /_app/api/v1/orgs/{org}/ai/ml-bom | components:read |
GET /_app/api/v1/orgs/{org}/ai/references?tool=&unpinned=true&repository=&model= | components:read |
PUT erstatter hele politikken: et felt, du udelader, får sin standardværdi.
curl -X PUT \
-H "Authorization: Bearer ${FREMFORGE_PAT}" \
-H "Content-Type: application/json" \
-d '{"mode":"enforce","allow_framework_pickles":false}' \
https://frem.sh/_app/api/v1/orgs/acme/security/model-policyEn afvisning kræver policy:write, ikke findings:write, fordi en afvist fil går
igennem håndhævelse. Et CI-jobs runner-token har det aldrig.
curl -X POST \
-H "Authorization: Bearer ${FREMFORGE_PAT}" \
-H "Content-Type: application/json" \
-d '{"reason":"Our own YOLO checkpoint, built in CI","expires_at":"2027-01-31"}' \
https://frem.sh/_app/api/v1/orgs/acme/security/model-findings/<sha256>/dismissSe API-referencen for svarenes format.
Hvad der ikke er dækket
- Filer vedhæftet issues, pull requests og releases samt pakkeuploads, hvis body indeholder mere end filen (PyPI, NuGet og andre multipart-uploads). De malwarescannes som hidtil.
- Modeller i dine repositoriers almindelige Git-objekter. Store modelfiler hører hjemme i Git LFS.
- Indlæsning eller kørsel af en model og at finde en bagdør i dens vægte. Ingen scanner kan skelne en forgiftet vægt fra en normal.