Paketrichtlinien
Eine Paketrichtlinie entscheidet Datei für Datei, ob ein Paket in der Registry deiner Organisation heruntergeladen werden darf. Sie deckt die Registry-Typen ab, die fremforge hostet: npm, Maven, PyPI, NuGet, Cargo, Go, Conda, CRAN, Debian, RPM, Helm und generische Pakete sowie Container-Images (siehe Container-Images). Jede Organisation hat eine Richtlinie, mit optionalen Einstellungen pro Pakettyp.
Was eine Richtlinie prüft
Wenn eine Datei veröffentlicht wird, entpackt fremforge sie, listet die darin mitgelieferten Komponenten auf und liest die vom Paket selbst angegebene Lizenz (siehe SBOMs). Jede Komponente wird mit den OSV-Advisories abgeglichen, und das jeden Tag aufs Neue. Die Richtlinie wird gegen diese Ergebnisse ausgewertet, und die Bewertung wird für die Datei gespeichert: allow, warn oder block. Eine Änderung an der Richtlinie, einer Liste oder einer Ausnahme bewertet jede Datei sofort neu, ohne erneuten Scan.
Beim Download entscheidet die gespeicherte Bewertung. Das gilt für Downloads über
die Registry-API (/api/packages/…, die jeder Paketmanager nutzt) und über die
Weboberfläche. Paket-Metadaten, etwa ein npm-Packument oder ein PyPI Simple
Index, werden nie gefiltert. Sobald die Durchsetzung eingeschaltet ist, erhält
ein Resolver, der eine blockierte Version anfragt, für diese Datei 403; er wird
nicht auf eine andere Version umgelenkt.
Schwachstellen
| Einstellung | Bedeutung |
|---|---|
vuln_min_severity | Blockiert eine Datei mit einer offenen Advisory ab diesem Schweregrad: low, medium, high oder critical. |
vuln_min_cvss | Blockiert ab diesem CVSS-Basiswert (0–10). Der Wert wird aus dem CVSS-Vektor der Advisory berechnet. |
vuln_require_fix_available | Zählt nur Advisories, für die es eine behobene Version gibt. |
vuln_min_epss | Zählt nur Advisories, deren EPSS-Wahrscheinlichkeit mindestens diesen Wert erreicht (0–1). Eine Advisory ohne EPSS-Wert zählt nicht. |
Die Schwachstellenregel ist nur eingeschaltet, wenn ein Schwellenwert für den Schweregrad oder für CVSS gesetzt ist. Sind beide gesetzt, zählt eine Advisory, die einen der beiden erreicht.
Lizenzen
Lizenzen sind SPDX-Kennungen und werden sowohl gegen die angegebene Lizenz als auch gegen die in mitgelieferten Komponenten erkannten Lizenzen geprüft.
Die Lizenzlisten werden auf der Seite Lizenzrichtlinie
festgelegt, ein Regelsatz für Pull Requests und Downloads. Die Seite
Paketrichtlinien verlinkt dorthin. Die folgenden Felder sind die Download-Seite
dieser Richtlinie, und PUT /orgs/{org}/package-policy akzeptiert sie weiterhin.
| Einstellung | Bedeutung |
|---|---|
licence_allow | Wenn nicht leer, sind nur diese Lizenzen erlaubt. |
licence_deny | Diese Lizenzen blockieren. |
licence_warn | Diese Lizenzen lösen eine Warnung aus. |
licence_unknown_action | Was passiert, wenn eine Lizenz kein gültiger SPDX-Ausdruck ist oder fehlt: allow, warn oder block. |
licence_multiple_mode | Für einen Ausdruck mit mehreren Lizenzen (MIT OR GPL-3.0-only): any_allowed besteht, wenn eine davon erlaubt ist, all_allowed verlangt alle. |
Ausdrücke werden pro Operand ausgewertet. OR besteht, wenn irgendein Operand
erlaubt ist, AND verlangt jeden Operanden, und X WITH exception wird als X
ausgewertet.
Zulassungs- und Sperrlisten
Eine Listenregel nennt einen Pakettyp (oder jeden Typ), ein Namensmuster
(Platzhalter * und ?, zum Beispiel @acme/* oder
org.apache.logging.log4j:log4j-core) und optional einen Versionsbereich in
vers:-Syntax, zum Beispiel
vers:maven/<2.17.1. Bereiche folgen den Versionsregeln des jeweiligen
Ökosystems für npm, Cargo und Go (Semver), PyPI (PEP 440), Maven und NuGet.
match_target: packagetrifft auf das Paket zu, das du veröffentlicht hast.match_target: componenttrifft auf eine darin mitgelieferte Komponente zu.
Eine deny-Regel blockiert. Eine allow-Regel für ein Paket lässt es an den Regeln für Schwachstellen, Lizenzen und Alter vorbei, und eine allow-Regel für eine Komponente nimmt diese Komponente von den Regeln für Schwachstellen und Lizenzen aus. Allow-Regeln heben nie bekannte Malware oder eine deny-Regel auf. Eine Regel kann ein Ablaufdatum tragen.
Mindestalter
min_age_hours hält Dateien zurück, die vor weniger als so vielen Stunden
veröffentlicht wurden, optional nur für die Typen in age_types. Das Alter wird
im Moment des Downloads bestimmt, sodass eine Datei herunterladbar wird, sobald
sie alt genug ist. Das Speichern des Release-Alters
der Organisation setzt es auf entsprechend viele Tage (0 schaltet es aus); ein
Typ mit eigenem Mindestalter in type_overrides behält dieses.
Eine Version, die eine bekanntermaßen ausgenutzte Schwachstelle behebt (eine CVE, die in der EU Vulnerability Database der ENISA oder im KEV-Katalog der CISA geführt wird), wird nicht zurückgehalten: Eine Korrektur für eine Schwachstelle, die tatsächlich ausgenutzt wird, soll nicht warten. Die Altersregel erscheint trotzdem in der Entscheidung, als aufgehoben markiert mit der CVE, für die sie aufgehoben wurde, sodass die Aufhebung in der Bewertung, im Audit-Log und im SIEM sichtbar ist. Eine Korrektur für eine CVE, die nicht als ausgenutzt bekannt ist, wartet wie gewohnt.
Immer aktiv
Zwei Prüfungen laufen unabhängig davon, was die Richtlinie sagt, auch im Modus Aus:
- Bekannte Malware. Eine Datei, die ein Paket enthält, das in einer
OSV-Advisory
MAL-*geführt wird, wird in jedem Modus mit403abgelehnt, auch in Schatten und Aus. Um eine einzelne Datei durchzulassen, braucht es eine genehmigte Ausnahme für die Regelmalware. Siehe Schädliche Pakete. - Namenskollision. Eine Advisory, die den Namen und die Version deines eigenen Pakets nennt, meist weil ein öffentliches Paket denselben Namen trägt, erzeugt eine Warnung. Sie blockiert nie.
Container-Images
Ein Container-Image wird pro Manifest-Digest gegen dieselben Regeln ausgewertet, mit den eigenen Eingaben des Images:
- Schwachstellen sind die CVE-Befunde des
Container-Image-Scannings für diesen Digest
(oder seinen Tag), mit Schweregrad und CVSS-Wert. Image-Befunde haben keinen
EPSS-Wert, daher zählt eine Richtlinie mit gesetztem
vuln_min_epsssie nicht. Ein verworfener Befund zählt nicht. - Malware ist ein offener Befund zu schädlichen Paketen für diesen Digest.
- Lizenzen sind die, die der Image-Scan für die Pakete im Image meldet. Ein Paket ohne Lizenz zählt als unbekannt.
- Zulassungs- und Sperrlisten treffen auf das Image als Typ
container(sein Name und Tag) und auf die Pakete darin als Komponenten zu. - Mindestalter zählt ab dem Push des Tags, wenn
containerinage_typessteht (oderage_typesleer ist).
Das Image wird beim Pull geprüft (docker pull oder jeder Client, der
/v2/…/manifests/… liest), für jedes Manifest, das der Pull ausliefert,
einschließlich jeder Plattform eines Multi-Plattform-Images. Images laufen nur
im Schattenmodus: Ein Pull, der gegen die Richtlinie verstößt, wird unter
Wäre blockiert worden erfasst und nie abgelehnt, egal welchen Modus du wählst.
Image-Befunde werden mindestens alle 12 Stunden neu bewertet, und sofort, wenn du
die Richtlinie, eine Liste oder eine Ausnahme änderst.
Das ist unabhängig von den bestehenden Pull-Sperren für Images, die unverändert
bleiben: Die Einstellung block_pull des
Container-Image-Scannings und die Sperre für
schädliche Pakete lehnen Pulls schon heute ab.
Signaturen
signature_requirement prüft die Signaturen von npm-Paketen, die deine
Organisation über den Abhängigkeits-Proxy von fremforge von npmjs.org bezieht,
sobald der Abhängigkeits-Proxy für deine Organisation verfügbar ist, und zwar
bevor der Tarball ausgeliefert wird:
- die Registry-Signatur, die npmjs.org über jede Version erstellt
(
name@version:integrity), geprüft gegen die von npm veröffentlichten Registry-Schlüssel; - die Build-Provenienz, wenn die Version eine hat: eine mit Sigstore signierte SLSA-Attestierung, offline gegen den öffentlichen Sigstore-Trust-Root geprüft und an den SHA-512 des Tarballs gebunden.
| Einstellung | Bedeutung |
|---|---|
off | Nicht geprüft. Der Standard. |
if_present | Eine vorhandene Signatur oder Provenienz muss gültig sein. Eine Version ohne besteht. |
require | Wie if_present, und eine Version muss eine gültige Signatur tragen (oder, wenn Signierer eingetragen sind, vertrauenswürdige Provenienz). |
signature_identities listet die Build-Identitäten auf, denen du vertraust,
jeweils ein OIDC-issuer und eine subject_regex, auf die das gesamte
Zertifikats-Subject passen muss. Ist mindestens eine eingetragen, zählt nur
Provenienz von einer davon; eine Registry-Signatur allein nicht, denn sie belegt,
was npmjs.org ausgeliefert hat, nicht, wer es gebaut hat. Für Pakete, die mit
GitHub Actions in einer Organisation gebaut werden:
"signature_requirement": "require",
"signature_identities": [
{ "issuer": "https://token.actions.githubusercontent.com",
"subject_regex": "https://github\\.com/sigstore/.+" }
]Wie jede Regel folgt sie dem Modus der Richtlinie. Eine Version, die
durchfällt, wird mit der Regel signature und einem Grund wie
no provenance from a trusted identity oder the registry signature does not verify erfasst. Eine genehmigte Ausnahme mit der Regel
signature lässt sie durch.
Was nicht geprüft wird: Pakete, die auf frem.sh veröffentlicht wurden (die
Registry speichert für sie keine npm-Signatur und keine Provenienz, daher gilt
die Regel für sie überhaupt nicht), und alle anderen Pakettypen. Maven-Signaturen
(.asc) und NuGet-Signaturen werden nicht geprüft.
Herabgestufte Provenienz
provenance_downgrade erkennt eine Version, deren Build-Provenienz schwächer
ist als die der vorigen Version. Das ist die typische Spur eines Releases, das
von einem Laptop oder mit einem gestohlenen Token veröffentlicht wurde, nachdem
die früheren Releases aus der CI kamen. Es nutzt dieselben geprüften Fakten wie
die Signaturen und gilt daher für npm-Pakete, die über den
Abhängigkeits-Proxy von npmjs.org bezogen werden.
Die vorige Version ist die höchste niedrigere Version, die früher veröffentlicht wurde. Ein Backport auf einer älteren Linie, etwa eine Sicherheitskorrektur 4.5.x, die nach 5.4.x erscheint, wird also mit dem vorigen Release dieser Linie verglichen, nicht mit dem neuesten. Ältere Linien werden oft noch ohne Provenienz gebaut.
Eine Version gilt als Herabstufung, wenn die vorige Version Build-Provenienz hatte und diese Version:
- gar keine Provenienz hat;
- Provenienz hat, die nicht verifiziert werden kann; oder
- von einem anderen Signierer gebaut wurde: einem anderen OIDC-Aussteller, Quell-Repository oder Build-Workflow, oder auf einem selbst gehosteten Runner, wo die vorige Version auf einem gehosteten lief. Diese Angaben werden aus dem geprüften Sigstore-Zertifikat gelesen. Ein neuer Tag desselben Workflows ist derselbe Signierer.
Die erste Version eines Pakets und eine Version, deren Vorgänger keine Provenienz
hatte, bestehen immer. Diese Regel vergleicht Versionen. Um Provenienz für jede
Version zu verlangen, nutze signature_requirement.
| Einstellung | Bedeutung |
|---|---|
off | Nicht geprüft. Der Standard. |
warn | Eine Herabstufung wird als Warnung erfasst; die Version wird ausgeliefert. |
block | Eine Herabstufung blockiert die Version. Wie bei jeder Regel entscheidet der Modus der Richtlinie: enforce lehnt den Download ab, shadow erfasst ihn nur. |
"provenance_downgrade": "block"In der Konsole findest du sie unter Richtlinien › Paketrichtlinien ›
Signaturen. Mit Terraform ist es das Argument provenance_downgrade von
fremforge_package_signature_policy. Sie lässt sich auch für einen einzelnen
Pakettyp in type_overrides setzen.
Eine Version, die durchfällt, wird mit der Regel provenance_downgrade und einem
Grund erfasst, der die vorige Version nennt, zum Beispiel
2.4.1 has no build provenance, but the previous version 2.4.0 had oder
... built by a different signer than the previous version 2.4.0: source repository https://github.com/acme/lib -> https://github.com/fork/lib. Eine
genehmigte Ausnahme mit der Regel signature und dem Selektor
provenance_downgrade nimmt nur diese Regel aus. Eine Ausnahme mit der Regel
signature ohne Selektor nimmt beide Signaturregeln aus.
Wo sie noch nicht gilt:
| Ökosystem | Warum |
|---|---|
| PyPI | PyPI veröffentlicht Attestierungen nach PEP 740, aber fremforge prüft sie noch nicht. |
| Maven Central, RubyGems | Signieren mit Sigstore ist upstream optional und wird vom Proxy nicht geprüft. |
| Cargo, Go, NuGet, Composer, Helm, conda, Debian, RPM, Terraform-Module | Upstream gibt es keine Build-Provenienz pro Version. Signaturen von Repositorys oder Prüfsummen-Datenbanken belegen die Integrität, nicht, wer eine Version gebaut hat. |
| Auf frem.sh veröffentlichte Pakete | Für sie wird keine Provenienz erfasst. |
Auch die Lockfile-Prüfung des Proxys und seine Filterung von Paket-Metadaten wenden sie nicht an; bewertet wird beim Download eines Tarballs.
Einstellungen pro Typ
type_overrides setzt jede der obigen Regeln für einen Pakettyp anders, zum
Beispiel eine strengere Lizenzliste für npm. "enabled": false schaltet die
Richtlinie für diesen Typ aus, abgesehen von der Malware-Prüfung.
Modi
| Modus | Was passiert |
|---|---|
off | Nur bekannte Malware und Namenskollisionen werden geprüft. |
shadow | Jede Regel wird ausgewertet. Nichts wird abgelehnt, und jeder Download, der abgelehnt worden wäre, wird erfasst. Das ist der Standard. |
enforce | Ein Download, der gegen die Richtlinie verstößt, wird mit 403 abgelehnt. Die Antwort nennt die zutreffenden Regeln und verlinkt auf die Seite der Richtlinie. |
pending_action legt fest, was mit einer Datei passiert, deren Bewertung noch
nicht abgeschlossen ist, etwa einer Datei, die vor Sekunden veröffentlicht wurde.
allow (der Standard) lässt sie durch. refuse antwortet mit 503 und
Retry-After, nur im Modus enforce.
Ausnahmen
Eine Ausnahme lässt ein Paket für begrenzte Zeit an einer Regel vorbei. Sie braucht eine zweite Person: Die antragstellende Person kann ihren eigenen Antrag nicht genehmigen, und die genehmigende Person muss Owner der Organisation sein oder auf der Genehmigungsliste der Organisation stehen.
Eine Ausnahme hat:
- einen Geltungsbereich: eine Datei, einen Versionsbereich eines Pakets, jede Version eines Pakets oder eine mitgelieferte Komponente (per purl);
- eine Regel:
vuln,licence,age,deny_list,name_clashodermalware, optional eingeschränkt auf eine Advisory-ID oder eine SPDX-Lizenz; - eine Begründung;
- ein Ablaufdatum höchstens 366 Tage in der Zukunft. Es ist Pflicht.
Eine Ausnahme wird beantragt und dann genehmigt oder abgelehnt. Eine genehmigte
Ausnahme kann jederzeit widerrufen werden und wird bei ihrem Ablauf automatisch
widerrufen. Jeder Schritt wird ins Audit-Log
geschrieben (package_policy.exception.*).
Ausnahmen von der Paketrichtlinie teilen sich Warteschlange, API und Einstellungen mit Ausnahmen für Befunde: siehe Ausnahmen, wo auch das Genehmigungs-Team, die Obergrenze für das Ablaufdatum und der automatische Widerruf beschrieben sind.
Die Ansicht „Wäre blockiert worden"
Öffne die Admin-Seiten deiner Organisation unter Sicherheit › Richtlinien › Paketrichtlinien. Die Seite hat vier Ansichten:
- Richtlinie legt den Modus und die Regeln fest und zeigt die aktuellen Bewertungen deiner veröffentlichten Dateien. Um zu sehen, was neue Einstellungen blockieren würden, bevor du sie speicherst, nutze den Testlauf in der API (unten).
- Zulassungs- und Sperrlisten enthält die Listenregeln.
- Ausnahmen zeigt Anträge, die Genehmigungswarteschlange und den Verlauf. Bei deinen eigenen Anträgen fehlt die Schaltfläche Freigeben.
- Wäre blockiert worden listet die Downloads der letzten 14 Tage auf, die die Richtlinie abgelehnt hat oder im Schattenmodus abgelehnt hätte: eine Zeile pro Datei, Regel, Nutzer und Tag, mit der Zahl der Downloads. Das ist der Nachweis, den du prüfen solltest, bevor du eine Organisation auf Durchsetzen umstellst.
Auf diese Weise abgelehnte oder erfasste Downloads stehen auch im
Zugriffsprotokoll der Registry mit der Entscheidung
would_block oder blocked.
Was sich mit dem Start der Durchsetzung geändert hat
Am 2026-10-11:
- Der Modus Durchsetzen lehnt ab. Vorher erfasste Durchsetzen dieselben Ergebnisse wie Schatten. Stand deine Richtlinie bereits auf Durchsetzen, werden Downloads, die gegen sie verstoßen, jetzt abgelehnt. Prüfe zuerst Wäre blockiert worden, oder stelle auf Schatten um, bis du das getan hast.
- Bekannte Malware wird für alle abgelehnt. Vorher wurde sie nur erfasst.
- Deine Ergebnisse werden angezeigt. Bewertungen von Dateien, Wäre blockiert worden, Paketbefunde sowie die APIs für Bewertung, Testlauf, Entscheidungen und Befunde antworten jetzt für deine Organisation. Seitdem erzeugen Paketbefunde und Richtlinienentscheidungen auch Ereignisse im Audit-Log (und damit SIEM- und Webhook-Ereignisse), Sicherheitswarnungen per E-Mail, Zeilen im wöchentlichen Digest und Zeilen im Tab Malware, für Änderungen ab diesem Tag. Wäre blockiert worden listet auch die Downloads auf, die in den 14 Tagen davor erfasst wurden.
- Container-Images sind unverändert: weiterhin nur Schattenmodus, siehe Container-Images.
API
Nutze ein Token mit policy:read oder policy:write (findings:read für
Paketbefunde). Basis-URL: https://frem.sh/_app/api/v1. Die vollständigen
Request- und Response-Strukturen stehen in der API-Referenz.
| Methode und Pfad | Was es tut |
|---|---|
GET /orgs/{org}/package-policy | Die Richtlinie, mit ihrer version. |
PUT /orgs/{org}/package-policy | Die Richtlinie ändern. Sende die version, die du gelesen hast; eine veraltete Version erhält 409 policy-version-conflict. |
GET, POST /orgs/{org}/package-policy/rules | Zulassungs- und Sperrregeln auflisten oder hinzufügen. Eine Regel braucht list, name_glob und reason. |
DELETE /orgs/{org}/package-policy/rules/{id} | Eine Regel entfernen. |
GET, PUT /orgs/{org}/package-policy/approvers | Die benannten genehmigenden Personen neben den Ownern. PUT nimmt {"logins": [...]}. |
GET, POST /orgs/{org}/package-policy/exceptions | Ausnahmen auflisten (Filter mit status) oder eine beantragen. |
GET /orgs/{org}/package-policy/exceptions/{id} | Eine Ausnahme. |
POST /orgs/{org}/package-policy/exceptions/{id}/approve | Genehmigen. Abgelehnt mit self-approve für die antragstellende Person und mit not-an-approver für alle anderen, die nicht genehmigen dürfen. |
POST /orgs/{org}/package-policy/exceptions/{id}/reject | Ablehnen. |
DELETE /orgs/{org}/package-policy/exceptions/{id} | Widerrufen. |
GET /orgs/{org}/package-policy/evaluation?type=&name=&version= | Die Bewertung jeder Datei einer Paketversion, mit Gründen, Befunden und Lizenzen. |
POST /orgs/{org}/package-policy/evaluate | Testlauf. Mit {"policy": {...}} meldet er, was jede aktuelle Datei unter diesen Einstellungen bekäme, und schreibt nichts. Mit {"components": [{"purl": "...", "licence": "..."}]} bewertet er eine Liste von Komponenten, zum Beispiel aus einem CI-Schritt, bevor du veröffentlichst. |
GET /orgs/{org}/package-policy/decisions | Die Daten für Wäre blockiert worden: days (1–90, Standard 14), decision (blocked, would_block oder pending_refused). |
GET /orgs/{org}/findings/packages | Advisory-Befunde zu Registry-Paketen. Blättere mit cursor (der next_cursor der vorigen Seite) und limit (bis zu 500). |
Eine Richtlinie im Schattenmodus, die hohe und kritische Advisories sowie AGPL blockiert und neue npm-Releases 24 Stunden lang zurückhält:
TOKEN=ffp_...
ORG=acme
V=$(curl -sS -H "Authorization: Bearer $TOKEN" \
"https://frem.sh/_app/api/v1/orgs/$ORG/package-policy" | jq .version)
curl -sS -X PUT -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
"https://frem.sh/_app/api/v1/orgs/$ORG/package-policy" \
-d "{\"version\": $V, \"mode\": \"shadow\", \"vuln_min_severity\": \"high\",
\"licence_deny\": [\"AGPL-3.0-only\", \"AGPL-3.0-or-later\"],
\"min_age_hours\": 24, \"age_types\": [\"npm\"]}"log4j-core unter 2.17.1 sperren, wo immer es mitgeliefert wird:
curl -sS -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
"https://frem.sh/_app/api/v1/orgs/$ORG/package-policy/rules" \
-d '{"list": "deny", "pkg_type": "maven", "name_glob": "org.apache.logging.log4j:log4j-core",
"version_range": "vers:maven/<2.17.1", "match_target": "component",
"reason": "Log4Shell"}'Audit
Jede Änderung steht im Audit-Log: package_policy.updated
(mit dem, was sich geändert hat), package_policy.rule.created und .deleted,
package_policy.approvers.updated, die Ausnahme-Ereignisse und
package_policy.verdict_changed, wenn eine Datei von allow in Richtung warn oder
block wechselt. Ein abgelehnter oder ein Download, der abgelehnt worden wäre,
wird als package_policy.download_blocked oder
package_policy.download_would_block erfasst, einmal pro Datei, Regel, Nutzer
und Tag.
Verwandte Themen
- Schädliche Pakete
- Container-Image-Scanning, das eine eigene Pull-Sperre für Container-Images hat
- SBOMs
- Zugriffsprotokoll der Registry