Hoppa till huvudinnehållet

Modellskanning

En modellfil kan köra kod när den läses in. En PyTorch-checkpoint är en Python-pickle, och att packa upp den kan importera och anropa vad som helst. Keras Lambda-lager, chattmallar i GGUF och anpassade operatorer i ONNX är andra vägar in. fremforge skannar modellfiler var de än hamnar i din organisation och sparar en dom per fil. Organisationens policy avgör vad som händer med en fil som skanningen hittar.

Ingen modell läses någonsin in eller körs för att skannas. Skannern läser filens struktur: pickle-filens importlista, huvudena i safetensors och GGUF, ONNX-grafen och Keras-konfigurationen.

Var modellfiler hittas

YtaNär den skannasVad Tvinga gör
Git LFSVid uppladdningNekar uppladdningen med 422
Paket (generiska, och varje typ vars uppladdningsbody är filen)Vid uppladdningNekar uppladdningen med 422
Container-registry (ModelPack, KitOps, Docker ai/ och modellfiler i vanliga images)Efter pushenNekar en hämtning som skulle leverera lagret med 403
Beroendeproxy (container-images)När den hämtas första gångenNekar senare hämtningar av lagret med 403
Actions-artefakterNär körningen är klarIngenting. Artefakter får bara fynd

En fil känns igen som en modell på sina första byte, inte på sitt namn. En pickle som sparats som weights.txt hittas ändå.

Format och domar

FormatVad som kontrolleras
Pickle, joblib, PyTorch (.pt, .pth, .bin, äldre och zip), NumPy-objektarrayerVarje import i pickle-filen mot en tillåtelselista. Tillåtelselistan är det som PyTorchs torch.load(weights_only=True) accepterar, plus de NumPy-typer som en state dict behöver
safetensorsHuvudet: längder, datatyper och offset, och att filen inte också kan öppnas som zip eller pickle
GGUFMetadata, chattmallen (mot en säker delmängd av Jinja) och samma zip- och pickle-kontroller
ONNXDomäner för anpassade operatorer, och sökvägar för extern data som lämnar modellens katalog
Keras (.keras, .h5)Lambda-lager och anpassade objekt utanför Keras-namnrymden

Varje fil får en dom, som delas av alla organisationer som har samma byte:

  • clean (ren): ingenting hittades.
  • Misstänkt (suspicious): en import utanför tillåtelselistan (pickle-unknown-import), en klass från ett känt ML-ramverk (pickle-framework-object, se Ramverks-pickles), en konstruktion i en GGUF-mall utanför den säkra delmängden, en anpassad ONNX-operator, eller en fil som också kan öppnas som ett annat format.
  • Skadlig (malicious): en import på skannerns blockeringslista (till exempel os.system eller builtins.eval), eller ett Keras Lambda-lager.
  • Kan inte skannas (unscannable): filen kunde inte läsas till slutet: en trasig zip, ett 7z-arkiv, en avkortad ström.
  • format-verified (formatverifierad): en safetensors- eller GGUF-fil över 4 GiB vars strukturkontroll gick igenom. Se Över 4 GiB.

Skannern är öppen källkod: picklescan för genomgången av pickle-filen, med fremforges tillåtelselista ovanpå.

Organisationens policy

Policyn har tre lägen. Ställ in den under Säkerhet › Policyer › Modellskanning, eller med API:t.

LägeVad som händer
Skugga (standard)Varje fil skannas och de filer som policyn skulle blockera listas som fynd. Ingenting nekas.
TvingaSom skugga, och filerna med ett öppet fynd nekas, enligt listan under Var modellfiler hittas.
AvFilerna skannas fortfarande och fynden listas fortfarande, men ingenting nekas eller räknas som skulle-blockeras.

I läget Tvinga blockerar policyn en fil vars dom är Skadlig, Kan inte skannas eller Misstänkt, om inte fyndet har avfärdats. En fil som är clean eller format-verified går alltid igenom.

Hur Tvinga ser ut

En uppladdning som nekas svarar 422 med domen, fyndkoderna och filens sha256:

{
  "error": "model file rejected",
  "rule": "suspicious",
  "verdict": "suspicious",
  "findings": ["pickle-unknown-import"],
  "sha256": "d24ec017bdcf45a8737b4a9398e6eea64fa37a5821f473041cb3bc03f8489687"
}

En fil som inte har skannats tidigare skannas under uppladdningen. Det lägger till högst några sekunder för en fil på upp till 256 MiB. En safetensors- eller GGUF-fil över 256 MiB kontrolleras via sitt huvud och sina sista 64 KiB. Alla andra modellfiler över 256 MiB accepteras och skannas direkt efter uppladdningen, så de dyker upp som ett fynd en minut senare i stället för att nekas.

Om skannern inte går att nå svarar en uppladdning av en modellfil i en organisation som tvingar 503 med Retry-After: 30. Uppladdningar av andra filer påverkas inte.

En container-hämtning som skulle leverera ett blockerat lager svarar 403 DENIED, med orsaken model-malicious, model-suspicious eller model-unscannable och lagrets digest. Ett modellager som du nyss har pushat skannas inom ungefär en minut. Fram till dess svarar en hämtning 403 med orsaken model-scan-pending, på samma sätt som för en image med ett lager som fortfarande skannas efter skadlig kod. Hämtningar från runners som hostas av fremforge hålls inte tillbaka för en skanning som väntar.

git-lfs döljer orsaken. För en nekad uppladdning skriver git-lfs Uploading failed due to unsupported Content-Type header(s), och git lfs push --object-id avslutar med 0. En vanlig git push misslyckas däremot. Orsaken finns i svarets body, och filen listas som ett fynd under Modellskanning.

Ramverks-pickles

Vissa checkpoints lagrar hela Python-objekt, inte bara vikter: en YOLO-modell, en TrainingArguments-fil, en scikit-learn-pipeline. Att läsa in en sådan kör den klassens kod. Skannern märker dessa pickle-framework-object när varje import utanför vikternas tillåtelselista kommer från ett känt ramverk: PyTorch-moduler, Transformers, Ultralytics, scikit-learn, joblib, timm, Lightning, SpeechBrain eller Diffusers.

De är Misstänkt som alla andra okända importer. För att släppa igenom dem i läget Tvinga slår du på Tillåt pickles från kända ML-ramverk (allow_framework_pickles). En fil med något annat fynd blockeras fortfarande.

Avfärda ett fynd

En organisationsägare kan avfärda ett fynd för en fil (en sha256), med en motivering och ett utgångsdatum: 90 dagar som standard, högst 365. En avfärdad fil går igenom Tvinga och försvinner ur listan över fynd. Avfärdanden gäller per organisation; en annan organisation som har samma byte påverkas inte. Ett avfärdande kan återkallas när som helst.

Över 4 GiB

Skannern för skadlig kod, ClamAV, kan inte läsa mer än 4 GiB av en fil, och fremforge nekar en fil som det inte kan skanna. För modellvikter, som ofta är större än 4 GiB, finns ett undantag, i alla lägen: en safetensors- eller GGUF-fil vars strukturkontroll går igenom accepteras som format-verified. De här formaten innehåller bara tensorer och metadata, och strukturkontrollen bevisar att filen inte innehåller något annat. Filen skannas inte efter skadlig kod.

Alla andra filer över 4 GiB, inklusive alla pickles, nekas fortfarande. Gränsen för en fil är 10 GiB. Stora modeller publiceras som shards på 5 GB eller mindre, så det här är sällan den gräns som spelar roll.

Actions-artefakter

När en arbetsflödeskörning är klar kontrolleras de filer den laddade upp med actions/upload-artifact efter modellfiler, och de skannas. Ett fynd listas under Modellskanning med repot, körningens nummer och artefakten. Artefakter nekas eller tas aldrig bort: att blockera en uppladdning skulle få ditt arbetsflöde att misslyckas utan möjlighet att åsidosätta det.

AI-inventering

Säkerhet › Komponenter › AI-inventering listar de maskininlärningsmodeller som din organisation har och de som dess CI hämtar. Den är skrivskyddad; policyn och avfärdandena finns kvar på sidan för modellskanning.

Modellfiler

En rad per modellfil (per sha256) som hittats i din Git LFS, dina paket, container-images, hämtningar via beroendeproxyn och Actions-artefakter, med:

  • dess format och storlek, och dess dom (pending medan den väntar på sin skanning);
  • dess licens, så som den är angiven (se Var licenser kommer från), med var den angavs. En modell utan angiven licens visar Okänd. fremforge gissar inte en licens utifrån ett filnamn;
  • vad dess huvud anger: antal parametrar, tensorernas datatyper, och för GGUF arkitekturen och modellnamnet;
  • var den förekommer: varje repo, paket, image eller artefakt där den setts.

Varje modellfil finns också i komponentinventeringen som pkg:generic/<file name>@<sha256>, så att en komponentsökning hittar den och “var används den” fungerar även för modeller. En modell som din CI hämtar från Hugging Face finns där som pkg:huggingface/<org>/<name>@<revision>, i det repo vars arbetsflöde hämtar den.

Var licenser kommer från

fremforge läser en licens bara från metadata som redan finns lagrad på fremforge, och frågar ingen annan: ingenting om dina modeller lämnar plattformen. I ordning:

  1. Själva filen: GGUF general.license, eller en licensnyckel i en safetensors-fils metadata.
  2. Den modellartefakt som filen är ett lager i, när du pushar den till organisationens registry eller hämtar den via beroendeproxyn. fremforge läser artefaktens små metadatablobbar från sin egen lagring, aldrig vikterna och aldrig uppströms-registryt:
    PaketeringLäses
    ModelPack (modctl)konfigurationens descriptor.licenses
    KitOps (kit)Kitfile: en modelldels license för den delen, sedan model.license, sedan package.license
    Docker Model Runner (docker model, ai/…)GGUF general.license i modellkonfigurationen, annars licensfilen i artefakten (application/vnd.docker.ai.license): Apache-2.0 och MIT känns igen på sin text, alla andra licenser på sin titel, till exempel LLAMA 3.2 COMMUNITY LICENSE AGREEMENT
    vilken som helst av demmanifestannoteringen org.opencontainers.image.licenses

API:t returnerar var varje licens angavs som licence_from, till exempel ModelPack config descriptor.licenses; AI-inventeringen visar det bredvid licensen. En licens från en image som du har pushat visas bara för din organisation. En modell som hämtades före den 13 oktober 2026 får sin licens från artefakten inom en timme, när artefakten fortfarande finns lagrad.

Modeller som din CI hämtar

Den dagliga arbetsflödesskanningen läser varje arbetsflöde på varje repos standardbranch, och de Python- och skalskript som ett arbetsflöde kör från samma repo (python scripts/fetch.py, bash ci/prepare.sh). Den hittar:

VerktygHittas som
Hugging Facefrom_pretrained("org/name"), hf_hub_download(repo_id=…), snapshot_download(…), huggingface-cli download, hf download
Ollamaollama pull name:tag
Dockerdocker model pull ref
KitOpskit pull ref
ModelPackmodctl pull ref

En referens är låst när den inte kan ändras under ditt bygge: en Hugging Face-modell med en fullständig commit-sha på 40 tecken som revision (revision="<sha>" eller --revision <sha>), och en Ollama-, Docker-, KitOps- eller ModelPack-modell med en @sha256:-digest. En branch eller tagg som main eller v1.0 är inte låst. Varje olåst referens är ett fynd, som en action som låsts till en tagg i stället för en commit.

Ett modellnamn som inte står skrivet i filen, till exempel from_pretrained(model_name), listas som Namn satt vid körning. En HF_ENDPOINT som sätts i samma fil visas, eftersom hämtningen då går till den endpointen i stället för huggingface.co. En referens som du tar bort försvinner inom tre dagar.

Hittas inte: oras pull (en ORAS-artefakt är en modell bara genom sin mediatyp, som kommandot inte visar; hämtad via beroendeproxyn klassificeras den utifrån sitt manifest), och Python-kod utanför de skript som ett arbetsflöde kör.

Licensen för en Hugging Face-modell som din CI hämtar via namn visas som Okänd: fremforge kontaktar inte Hugging Face, eller någon annan, för att slå upp den. En modell som din CI hämtar som OCI-artefakt via beroendeproxyn får sin licens från artefakten (se Var licenser kommer från).

ML-BOM

Ladda ned ML-BOM (CycloneDX) på sidan, eller GET /ai/ml-bom, returnerar inventeringen som ett CycloneDX 1.6-dokument. Varje modellfil är en komponent av typen machine-learning-model med sin sha256, sin angivna licens (var den angavs är egenskapen fremforge:model:licence_from), sin arkitektur som modelCard.modelParameters.modelArchitecture när huvudet anger en, och sitt format, sin dom, sina ytor, sin storlek, sitt antal parametrar och sina datatyper som egenskaper fremforge:model:*. Bara fakta som lästs från filen anges.

De SBOM:er som din CI laddar upp ändras inte: de är dina filer. ML-BOM:en är ett separat dokument.

Compliancerapport

Compliancerapporten har ett avsnitt AI-inventering: antalet modellfiler, de filer som din policy blockerar eller skulle blockera, filerna med ett avfärdat fynd, ditt läge för modellskanning, de modellhämtningar i CI som saknar fast revision, och filerna per angiven licens. Dess CSV listar varje modellfil. Avsnittet omfattar alltid hela organisationen, även i en rapport för ett enda repo.

Granskningslogg

HändelseNär
security_policy.model_scan.updatedLäget eller inställningen för ramverks-pickles ändrades
security_policy.model_scan.dismissedEtt fynd avfärdades, eller ett avfärdande förnyades
security_policy.model_scan.dismissal_revokedEtt avfärdande återkallades
registry.pull.blocked med gate: modelEn hämtning nekades av modellpolicyn

En nekad paketuppladdning eller container-hämtning finns också i åtkomstloggen för registry, med orsaken model_policy:<rule>. Åtkomstloggen omfattar inte Git LFS.

API

AnropScope
GET /_app/api/v1/orgs/{org}/security/model-policypolicy:read
PUT /_app/api/v1/orgs/{org}/security/model-policypolicy:write
GET /_app/api/v1/orgs/{org}/security/model-findings?status=open|dismissed|allfindings:read
POST /_app/api/v1/orgs/{org}/security/model-findings/{sha256}/dismisspolicy:write
DELETE /_app/api/v1/orgs/{org}/security/model-findings/{sha256}/dismissalpolicy: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-bomcomponents:read
GET /_app/api/v1/orgs/{org}/ai/references?tool=&unpinned=true&repository=&model=components:read

PUT ersätter hela policyn: ett fält som du utelämnar får sitt standardvärde.

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-policy

Att avfärda kräver policy:write, inte findings:write, eftersom en avfärdad fil går igenom Tvinga. Ett CI-jobbs runner-token har aldrig det scopet.

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>/dismiss

Se API-referensen för svarens form.

Vad som inte omfattas

  • Filer som bifogats till issues, pull requests och releaser, och paketuppladdningar vars body innehåller mer än filen (PyPI, NuGet och andra multipart-uppladdningar). Dessa skannas efter skadlig kod som tidigare.
  • Modeller i dina repons vanliga Git-objekt. Stora modellfiler hör hemma i Git LFS.
  • Att läsa in eller köra en modell, och att hitta en bakdörr i dess vikter. Ingen skanner kan skilja en förgiftad vikt från en normal.