Naar de hoofdinhoud

Uitzonderingen

Een uitzondering accepteert een risico voor beperkte tijd: een kwetsbaarheid die je nog niet kunt fixen, een licentiebevinding op een interne tool, een secret in een testfixture. Ze werkt op dezelfde manier voor elk soort bevinding (afhankelijkheden, containerimages, SAST, licenties, secrets, malware in afhankelijkheden, registrypakketten) en voor uitzonderingen op het pakketbeleid.

Een uitzondering gaat pas in als een tweede persoon haar goedkeurt. Tot dan blijft de bevinding openstaan en geldt het beleid nog steeds.

Het negeren van een bevinding is een uitzondering waarvoor geen goedkeuring nodig was. Genegeerde bevindingen, ook als ze voor een hele repository of een heel image zijn genegeerd, worden op dezelfde plek en via dezelfde API getoond, gelezen en ingetrokken als goedgekeurde uitzonderingen; zie Uitzonderingen zonder goedkeuring.

Hoe een uitzondering werkt

  1. Aanvragen. Iedereen die met bevindingen mag werken, vraagt er een aan, met een onderbouwing en een vervaldatum. Die datum mag hooguit het maximum van je organisatie in de toekomst liggen (366 dagen, tenzij je een lager maximum instelt).
  2. Goedkeuren of afwijzen. Een goedkeurder die niet de aanvrager is, beslist, met een optionele opmerking. De goedkeurders krijgen een e-mail zodra er een aanvraag binnenkomt, in hun eigen taal.
  3. Van kracht. De bevinding wordt genegeerd tot de vervaldatum. De bevinding legt vast wie de aanvraag deed (dismissed_by) en wie haar goedkeurde (dismissal_approved_by). Een nieuwe scan behoudt het negeren.
  4. Het einde. Op de vervaldatum gaat de bevinding weer open en wordt de uitzondering gemarkeerd als expired.

De statussen zijn requested, approved, rejected, expired en revoked.

Wie mag goedkeuren

Niemand kan zijn eigen aanvraag goedkeuren: de console toont diegene geen knop Goedkeuren, en de API antwoordt met self-approve. Een token zonder persoon erachter, en de inloggegevens van een AI-agent, kunnen helemaal niet over een uitzondering beslissen (user-identity-required).

Automatisch intrekken

Een goedgekeurde uitzondering wordt ingetrokken, en haar bevinding gaat direct weer open, wanneer:

AanleidingReden van intrekking
Iemand trekt haar met de hand inmanual
De ernst van de bevinding stijgt boven wat is goedgekeurdseverity_raised
Er verschijnt een nieuwe kwetsbaarheid op hetzelfde component (hetzelfde pakket en dezelfde versie, of hetzelfde imagepakket)new_vulnerability
De goedkeurder verlaat de organisatieapprover_left
De uitzondering steunde op het oordeel niet bereikbaar, en een latere scan vindt de bevinding bereikbaar of kan niet beslissenreachability_changed

Op het vertrek van de goedkeurder wordt gereageerd zodra het lidmaatschap verandert; de andere controles draaien elk uur. reachability_changed trekt ook het gewone negeren van een bevinding in dat steunde op het oordeel dat er geen aanroeppad is; zie Bereikbaarheid.

Audit en SIEM

Elke stap is een auditgebeurtenis van de tenant: code-security.exception.requested, .approved, .rejected, .revoked en .expired voor bevindingen, en package_policy.exception.* voor pakketbeleid. Een intrekkingsgebeurtenis bevat haar reden en wat er veranderde. Zoals elke auditgebeurtenis bereiken ze je SIEM-endpoints; filter op het actievoorvoegsel code-security.exception. om alleen deze te ontvangen.

In de console

Open Beveiliging › Bevindingen › Uitzonderingen. De pagina bevat:

  • Wacht op goedkeuring: de openstaande aanvragen, elk met Goedkeuren en Afwijzen en een opmerkingenveld. Bij je eigen aanvragen staat geen knop Goedkeuren.
  • Van kracht: goedgekeurde uitzonderingen, met Intrekken.
  • Geaccepteerd zonder goedkeuring: genegeerde bevindingen, ook die voor een hele repository of een heel image, met een filter op type en Intrekken. Zie Uitzonderingen zonder goedkeuring.
  • Historie: afgewezen, ingetrokken en verlopen uitzonderingen, met wie besliste, de opmerking en, bij een intrekking, waarom.
  • Een uitzondering voor een bevinding aanvragen: op de pagina van elke bevinding heeft het formulier om te negeren een link Uitzondering aanvragen (goedgekeurd door iemand anders) die dit voor je invult.
  • Instellingen: hoe lang een uitzondering hooguit mag lopen, het goedkeurdersteam en Negeren van bevindingen vereist goedkeuring.

API

Basis-URL https://frem.sh/_app/api/v1. Zie de API-referentie voor de volledige structuren.

Methode en padScopeWat het doet
GET /orgs/{org}/exceptionsfindings:readElke uitzondering die door een tweede persoon is goedgekeurd, de nieuwste eerst. Filter met status (kommagescheiden), kind (finding of package) en scanner. Voeg approval=none toe voor uitzonderingen zonder goedkeuring, of approval=all voor beide.
POST /orgs/{org}/exceptionsfindings:writeEr een aanvragen. Voor een bevinding: scanner, finding_id, justification, expires_at. Voor een pakketbeleid: "kind": "package" en de velden van een uitzondering op het pakketbeleid.
GET /orgs/{org}/exceptions/{id}findings:readEén uitzondering, goedgekeurd of niet.
POST /orgs/{org}/exceptions/{id}/approvefindings:writeGoedkeuren, met een optionele {"comment": "..."}.
POST /orgs/{org}/exceptions/{id}/rejectfindings:writeAfwijzen, met een optionele opmerking.
POST /orgs/{org}/exceptions/{id}/revokefindings:writeEen aanvraag terugtrekken, of een uitzondering intrekken. Voor een uitzondering voor een hele repository of een heel image is policy:write nodig.
GET, PUT /orgs/{org}/exceptions/settingspolicy:read, policy:writemax_days (1 tot 366), approver_team (een teamnaam, of null voor de eigenaren plus de lijst met goedkeurders) en dismissals_require_approval (true of false).

scanner is een van deps, images, sast, licenses, secrets, package_malware en packages; finding_id is de id die de endpoints voor bevindingen teruggeven. expires_at is een datum (YYYY-MM-DD, tot en met die dag in UTC) of een ISO 8601-tijdstip. Een tweede aanvraag voor een bevinding die al een openstaande of goedgekeurde uitzondering heeft, antwoordt met 409 duplicate-pending.

Een uitzondering aanvragen voor een bevinding in een afhankelijkheid:

curl -sS -X POST https://frem.sh/_app/api/v1/orgs/acme/exceptions \
  -H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
  -d '{"scanner":"deps","finding_id":"<id>","justification":"Not reachable from user input; fixed by the framework upgrade.","expires_at":"2026-12-31"}'

Een licentie-uitzondering voor het pakketbeleid:

curl -sS -X POST https://frem.sh/_app/api/v1/orgs/acme/exceptions \
  -H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
  -d '{"kind":"package","scope":"package","rule_kind":"licence","rule_selector":"GPL-3.0-only","pkg_type":"npm","name":"left-pad","justification":"Internal tool, never distributed.","expires_at":"2026-12-31"}'

Instellingen als code

PUT /orgs/{org}/exceptions/settings is een gewone idempotente schrijfactie, dus het maximum en het goedkeurdersteam kunnen in je configuratierepository staan, naast de rest van de instellingen van je organisatie:

curl -sS -X PUT https://frem.sh/_app/api/v1/orgs/acme/exceptions/settings \
  -H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
  -d '{"max_days": 90, "approver_team": "security"}'

Uitzonderingen zonder goedkeuring

De knop om een bevinding te negeren is de manier om haar door één persoon te laten accepteren. Hij legt vast wie negeerde en waarom, en kan een vervaldatum hebben. Er komt geen tweede persoon aan te pas, dus het is een uitzondering zonder goedkeuring. Gebruik een goedgekeurde uitzondering als je het vier-ogenprincipe nodig hebt, of zet Negeren van bevindingen vereist goedkeuring aan, zodat elke keer dat iemand die geen goedkeurder is een bevinding negeert, dat via zo’n uitzondering loopt.

Er zijn drie soorten, elk vermeld onder Geaccepteerd zonder goedkeuring in de console en via GET /orgs/{org}/exceptions?approval=none:

SoortscopeidWat het dekt
Negerenfindingdismissal.<scanner>.<hash>Eén bevinding. De id blijft gelijk over nieuwe scans heen. findings_count zegt hoeveel scanresultaten er nu onder vallen, bijvoorbeeld dezelfde bevinding op meerdere pull requests.
Afhankelijkheid negeren voor de hele repositoryreporepo.<uuid>Eén advisory in één pakket en manifest, in elke latere scan van de repository.
Negeren voor het hele imageimageimage.<uuid>Eén bevinding in een containerimage, in elke latere scan van het image.

Elk item heeft "approval": "none", "status": "approved" (van kracht) en dezelfde velden als elke uitzondering: justification is de reden van het negeren, requested_by wie negeerde, en expires_at de vervaldatum of null. Met approval=all hebben goedgekeurde uitzonderingen "approval": "required". Zonder de parameter approval is de lijst precies wat hij eerder was.

Een negeren dat is verlopen, wordt niet getoond: de dagelijkse vervaljob opent de bevindingen weer. Ook niet getoond: bevindingen die door een goedgekeurde uitzondering zijn genegeerd (de uitzondering is dan het item), bevindingen die vanzelf zijn verdwenen, en licentiebevindingen die je licentie-allowlist negeert, want die worden door die lijst geregeld.

Intrekken opent de bevindingen direct weer, en een bevinding met ernst high of critical geeft opnieuw een melding. Het intrekken van een negeren voor de hele repository of het hele image verwijdert ook de beslissing, zodat latere scans haar niet meer meenemen; daarvoor is policy:write nodig, net als voor DELETE /orgs/{org}/code-security/deps/repo-dismissals/{id}. Elke intrekking wordt geaudit: code-security.<scanner>.dismissal_revoked, of code-security.deps.repo_dismissal_revoked en code-security.images.repo_dismissal_revoked.

curl -sS "https://frem.sh/_app/api/v1/orgs/acme/exceptions?approval=none&scanner=deps" \
  -H "Authorization: Bearer $FREMFORGE_TOKEN"

curl -sS -X POST "https://frem.sh/_app/api/v1/orgs/acme/exceptions/dismissal.deps.3f1c0a9e5b7d2c4e6f8a0b1c/revoke" \
  -H "Authorization: Bearer $FREMFORGE_TOKEN"

Negeren vereist goedkeuring

Een instelling per organisatie, standaard uit. Staat ze aan, dan negeert iemand die geen goedkeurder is niets wanneer hij een bevinding in een afhankelijkheid, SAST, een secret, een containerimage, een licentie of malware in een afhankelijkheid negeert. In plaats daarvan:

  • krijgt elke openstaande bevinding een aanvraag voor een uitzondering, met de reden van het negeren als onderbouwing en de vervaldatum ervan (het maximum van je organisatie als er geen vervaldatum was);
  • blijft de bevinding openstaan, en krijgen de goedkeurders een e-mail;
  • keurt een goedkeurder die niet degene is die negeerde haar goed of af in de wachtrij. Goedkeuring negeert de bevinding met beide namen, precies zoals bij elke andere uitzondering. Niemand kan zijn eigen negeren goedkeuren.

Het negeren van een bevinding op een beschermde releasebranch is een uitzondering met de id branch.<finding id> en de scope branch. Die gaat nog niet via deze wachtrij: zolang deze instelling aanstaat, kan alleen een goedkeurder op een releasebranch negeren, en krijgt iedereen anders 403 approval-required.

Goedkeurders negeren nog steeds direct. In de console brengt een negeren dat ter goedkeuring is doorgestuurd je met een melding naar de wachtrij voor uitzonderingen. Via de API antwoordt elk endpoint om te negeren, ook in bulk, dan met 202 in plaats van 200:

{
  "dismissed": false,
  "status": "pending_approval",
  "pending_count": 1,
  "exceptions": [
    { "id": "<exception id>", "finding_id": "<finding id>", "status": "pending_approval", "expires_at": "2027-10-11T15:00:00.000Z" }
  ],
  "skipped": []
}

skipped somt de bevindingen op die niet in de wachtrij zijn gezet: not-found (niet openstaand, of niet van jou) of duplicate-pending (er is al een openstaande of goedgekeurde uitzondering). Het negeren van één bevinding antwoordt in die gevallen met 404 of 409 duplicate-pending. Een vervaldatum voorbij je maximum wordt geweigerd met 400 invalid-expires-at.

Een malwarebevinding op een geüpload bestand (Beveiliging › Bevindingen › Malwarescan van uploads) heeft geen reden of vervaldatum om door de wachtrij te sturen. Zolang de instelling aanstaat, kan alleen een goedkeurder er een negeren; iedereen anders krijgt 403 not-an-approver.

Zet haar aan onder Beveiliging › Bevindingen › Uitzonderingen › Instellingen, of via de API:

curl -sS -X PUT https://frem.sh/_app/api/v1/orgs/acme/exceptions/settings \
  -H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
  -d '{"dismissals_require_approval": true}'

of met exception_settings in de Terraform-module. Aan- of uitzetten schrijft de auditgebeurtenissen exceptions.dismissal_approval.enabled en .disabled. Een aanvraag die uit een negeren voortkomt, is de gewone gebeurtenis code-security.exception.requested met "via": "dismissal". Aanvragen die al wachten, blijven in de wachtrij als je de instelling uitzet, en kunnen nog steeds worden goedgekeurd.