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
- 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).
- 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.
- 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. - 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
- Standaard: de eigenaren van de organisatie en de mensen op de lijst met goedkeurders van het pakketbeleid.
- Of, als je in de instellingen een goedkeurdersteam opgeeft: alleen de leden van dat team.
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:
| Aanleiding | Reden van intrekking |
|---|---|
| Iemand trekt haar met de hand in | manual |
| De ernst van de bevinding stijgt boven wat is goedgekeurd | severity_raised |
| Er verschijnt een nieuwe kwetsbaarheid op hetzelfde component (hetzelfde pakket en dezelfde versie, of hetzelfde imagepakket) | new_vulnerability |
| De goedkeurder verlaat de organisatie | approver_left |
| De uitzondering steunde op het oordeel niet bereikbaar, en een latere scan vindt de bevinding bereikbaar of kan niet beslissen | reachability_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 pad | Scope | Wat het doet |
|---|---|---|
GET /orgs/{org}/exceptions | findings:read | Elke 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}/exceptions | findings:write | Er 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:read | Eén uitzondering, goedgekeurd of niet. |
POST /orgs/{org}/exceptions/{id}/approve | findings:write | Goedkeuren, met een optionele {"comment": "..."}. |
POST /orgs/{org}/exceptions/{id}/reject | findings:write | Afwijzen, met een optionele opmerking. |
POST /orgs/{org}/exceptions/{id}/revoke | findings:write | Een 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/settings | policy:read, policy:write | max_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:
| Soort | scope | id | Wat het dekt |
|---|---|---|---|
| Negeren | finding | dismissal.<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 repository | repo | repo.<uuid> | Eén advisory in één pakket en manifest, in elke latere scan van de repository. |
| Negeren voor het hele image | image | image.<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.