Push-bescherming
Elke push naar een fremforge-repository gaat door een Gitleaks-pre-receive-hook op de Forgejo-server, ook de allereerste push naar een nieuwe repository. Vindt de scanner een inloggegeven, dan wordt de push geweigerd en ziet de ontwikkelaar welke regel matchte (er lekt geen waarde en geen commit-SHA naar een derde partij).
Dit staat los van SAST-bevindingen en het scannen van containerimages: push-bescherming draait op het moment van git push, voordat de commits worden opgeslagen op een plek die fremforge moet beschermen. De andere scanners draaien later op het opgeslagen resultaat.
Wat wordt gematcht
De standaardregelset van Gitleaks plus aanvullingen van fremforge:
- Sleutels van cloudproviders (AWS, JSON van GCP-serviceaccounts, Azure SAS-tokens, T Cloud Public AK/SK)
- Gangbare API-sleutels van SaaS-diensten (Stripe, Mollie, SendGrid, Twilio, Lettermint, OpenAI)
- Generieke patronen met hoge entropie (PEM-privésleutels, JWT, SSH-privésleutels)
- Specifiek voor fremforge: persoonlijke toegangstokens (
ffp_*), OAuth-client-ID’s (ffc_*) en -secrets (ffs_*), OIDC-privésleutels van runners, bootstrap-inloggegevens voor OBS-buckets, HMAC-secrets voor het ondertekenen van acks
Het signaturenpakket van Gitleaks is vastgepind, wordt bij elke update gereviewd en wordt geleverd via dezelfde SWR-mirror als onze andere ontwikkeltools. We halen bij een push niets op uit de contentregistry van GitHub.
Je organisatie kan ook eigen patronen toevoegen, voor elke repository of voor één. Zie Eigen patronen. Ze worden bij het pushen op dezelfde manier toegepast, en een weigering noemt het regel-id van het patroon, custom-<name>.
Wat de ontwikkelaar ziet
Als een push een gematcht secret bevat, ziet de ontwikkelaar:
remote: Push rejected by fremforge push-protection.
remote:
remote: Matched rule: aws_access_key_id
remote: Path: src/services/uploader.ts:42
remote: Commit: <commit-sha>
remote:
remote: If this is a false positive, ask an org owner to add an
remote: override at frem.sh/<your-org>/_admin/push-protection.
remote: Override IDs are auditable and time-boxed.
remote: Or ask for this commit to be let through:
remote: https://frem.sh/_app/settings/push-protection/bypass/new?repo=<org>/<repo>&commit=<commit-sha>Er wordt geen waarde van een inloggegeven gelogd of teruggegeven. De ontwikkelaar heeft de broncode al open en kan het vals-positief zelf vinden.
Altijd aan, en de ene instelling
Push-bescherming kan niet worden uitgezet voor een organisatie of een repository. De enige instelling is de faalmodus van de scanner, onder Beveiliging › Beleid › Push-bescherming. Die bepaalt wat er met een push gebeurt als de scanner zelf niet beschikbaar is:
- Blokkeren (de standaard): de push wordt geweigerd met een duidelijke fout, en je probeert het opnieuw zodra de scanner hersteld is.
- Toestaan: de push gaat door en er wordt een allow-on-error-gebeurtenis vastgelegd in het audittrail. Secrets die in die periode zijn gepusht, worden later gevonden door de wekelijkse secretscan van de volledige geschiedenis.
De wijziging gaat in bij de volgende push en wordt vastgelegd in het auditlog.
Een nieuwe repository is beschermd vanaf de eerste push. De hook wordt gekoppeld als de repository wordt aangemaakt, dus ook een git push direct na het aanmaken wordt gescand.
Uitzonderingen
Beheerders van een tenant kunnen uitzonderingen toevoegen voor gevallen die de scanner verkeerd beoordeelt (testfixtures, voorbeeldfragmenten uit een SDK, documentatie die bewust de vorm van een sleutel toont).
- Tenantbeheer → Beveiliging › Beleid › Push-bescherming. Klap Actieve uitzonderingen open en klik op Uitzondering toevoegen. Vanuit een geweigerde push vult Goedkeuren… het formulier met de gegevens van die weigering.
- Kies wat de uitzondering dekt: alleen deze commit (een regel in één gepushte commit), alleen deze regel (elke match van één regel), alleen dit pad (een padglob zoals
test/fixtures/**), of een eigen combinatie. Elk veld dat je invult moet overeenkomen; een veld dat je leeg laat, komt met alles overeen. Minstens één van commit, regel en pad is verplicht. - Beperk de uitzondering eventueel tot één repository; anders geldt ze voor elke repository in de organisatie.
- Stel de vervaldatum in. Elke uitzondering loopt af: de datum staat standaard op 90 dagen na vandaag en ligt hoogstens 1 jaar in de toekomst. Een verlopen of ingetrokken uitzondering wordt niet meer gehonoreerd; voeg een nieuwe toe als je hem nog nodig hebt.
- Geef een reden op (verplicht, komt in het auditlog).
Hoe een push wordt beoordeeld. De pre-receive-hook verzamelt elk secret dat hij vindt in de commits die een push introduceert (regel, pad en regelnummer; nooit de waarde) en vraagt fremforge of elk ervan door een actieve uitzondering wordt gedekt. De push gaat alleen door als elke bevinding gedekt is; één niet-gedekte bevinding weigert hem zoals voorheen. Laat een uitzondering een push door, dan ziet de ontwikkelaar welke uitzondering(en) van toepassing waren, en wordt push-protection.override.used in het auditlog van je organisatie geschreven. Kan fremforge niet worden bevraagd (bijvoorbeeld tijdens een storing), dan wordt de push geweigerd: uitzonderingen falen nooit open. Een commit-uitzondering dekt de gepushte commit (de tip van de branch), en dat is de commit die een weigering noemt. Een secret in een archief wordt gematcht op het pad van het archief.
Uitzonderingen van vóór de limiet. Uitzonderingen die vóór 2026-10-18 zijn aangemaakt, konden zonder vervaldatum blijven. Ze werken gewoon door, en de console en het auditlog tonen ze als Geen vervaldatum (aangemaakt vóór de limiet). Trek er een in en maak hem opnieuw aan om hem een vervaldatum te geven.
Uitzonderingen gelden alleen voor push-bescherming. Een secret dat al in de geschiedenis staat en door de wekelijkse doorzoeking wordt vermeld, handel je af door de bevinding te negeren, niet met een uitzondering.
Via de REST API
Uitzonderingen, weigeringen en de faalmodus van push-bescherming zijn programmatisch te beheren: handig als je de onboarding van tenants scriptmatig doet, integreert met een CI-pipeline of aanstuurt vanuit een AI-agent.
- Uitzonderingen opvragen
GET /_app/api/v1/orgs/:slug/push-protection/overrides - Uitzondering aanmaken
POST /_app/api/v1/orgs/:slug/push-protection/overridesbody:{ "kind": "path", "path_pattern": "test/fixtures/**", "reason": "test fixtures", "expires_at": "2027-01-01T00:00:00Z" } - Uitzondering intrekken
DELETE /_app/api/v1/orgs/:slug/push-protection/overrides/:id - Faalmodus instellen
PUT /_app/api/v1/orgs/:slug/push-protection/failure-modebody:{ "mode": "block" }
Zonder expires_at verloopt een nieuwe uitzondering 90 dagen na het aanmaken; het antwoord bevat de datum. expires_at (een ISO 8601-datum of -tijdstempel) moet in de toekomst liggen en hoogstens 1 jaar weg zijn. Een latere datum wordt geweigerd met 400 expires-at-too-far, niet ingekort. In de lijst markeert no_expiry_legacy: true een uitzondering die vóór de limiet is aangemaakt, de enige soort met expires_at: null.
Voor het aanmaken of intrekken van een uitzondering is een token met policy:write nodig, omdat een uitzondering pushes vrijstelt van secretscanning; het runnertoken van een CI-job heeft die scope nooit. Ook voor het instellen van de faalmodus is policy:write nodig, omdat die push-bescherming voor de hele organisatie kan uitschakelen. Voor het opvragen is findings:read nodig, en voor het negeren van een weigering findings:write.
curl -X POST \
-H "Authorization: Bearer ${FREMFORGE_PAT}" \
-H "Content-Type: application/json" \
-d '{"kind":"path","path_pattern":"test/fixtures/**","reason":"test fixtures","expires_at":"2027-01-01T00:00:00Z"}' \
https://frem.sh/_app/api/v1/orgs/acme/push-protection/overridesZie de openbare REST API-referentie voor de volledige OpenAPI-specificatie.
Een omzeiling aanvragen
Een ontwikkelaar die geblokkeerd wordt, hoeft geen beheerder te zoeken om een uitzondering toe te voegen. De weigering toont een link naar een aanvraagformulier voor precies die commit. Iedereen in de organisatie met schrijfrechten op de repository kan het openen en een reden opgeven. De link bevat geen token, dus je moet inloggen om hem te gebruiken.
- Wie beslist. Eigenaren van de organisatie en de leden die je organisatie heeft aangewezen als goedkeurders van uitzonderingen. Wie de aanvraag deed, kan die nooit zelf goedkeuren. Zij krijgen een e-mail als er een aanvraag binnenkomt, en de webhookgebeurtenis
security.exception.requestedwordt verstuurd. - Wat een goedkeuring doet. Ze maakt een gewone uitzondering voor push-bescherming aan, gebonden aan die repository en die commit, 7 dagen geldig. Push je dezelfde commit binnen die tijd opnieuw, dan gaat hij door. Een andere commit met hetzelfde secret wordt nog steeds geblokkeerd en heeft een eigen aanvraag nodig.
- Hoe lang een aanvraag openstaat. Als niemand binnen 7 dagen beslist, verloopt de aanvraag.
- Wie kan goedkeuren, en hoe. Voor goedkeuren is iemand nodig die is ingelogd met tweefactorauthenticatie (of via je SSO), op de aanvraagpagina of met een OAuth-token van Forgejo op de API. Een API-token van de organisatie kan niet over een aanvraag beslissen.
- Geen vrijstellingen. Een geblokkeerde push van een bot doorloopt hetzelfde proces. Een lid met schrijfrechten vraagt namens de bot aan.
- Misbruiklimiet. Iemand kan per organisatie hoogstens 10 aanvragen per dag indienen.
- Wat er wordt getoond. De repository, de commit en de regel-id’s, nooit het secret. Aanvragen, beslissingen en de uitzondering worden vastgelegd in je auditlog (
push-protection.bypass.requested,.approved,.rejected,.cancelled). De aanvrager hoort de uitkomst per e-mail en webhook (security.exception.approvedofsecurity.exception.rejected).
Eigenaren zien openstaande en recente aanvragen op de pagina Push-bescherming, onder Omzeilingsaanvragen. Via de API:
- Opvragen
GET /_app/api/v1/orgs/:slug/push-protection/bypass-requests(?status=requestedvoor de openstaande) - Aanvragen
POST /_app/api/v1/orgs/:slug/push-protection/bypass-requestsbody:{ "repository": "app", "commit_sha": "<full sha>", "reason": "..." } - Beslissen
POST .../bypass-requests/:id/approveof.../reject, optioneel{ "comment": "..." } - Intrekken
POST .../bypass-requests/:id/cancel(alleen de aanvrager)
Omzeilen bij inloggegevens die al gelekt zijn
Een blokkade door push-bescherming betekent niet dat het inloggegeven veilig is. Op het moment dat je tegen de blokkade aanloopt, staat er een inloggegeven in een commit op je laptop. Roteer het inloggegeven voordat je iets anders doet. Daarna kun je de commit met een rebase uit de branch halen of pushen met een uitzondering; beide routes werken zodra het inloggegeven onbruikbaar is.
Pushes en de committerregel
Elke push wordt ook vastgelegd met het account dat hem authenticeerde (HTTPS-token, OAuth-token, SSH-sleutel, deploy key of Actions-job), en je organisatie kan eisen dat nieuwe commits een van de bevestigde e-mailadressen van de pusher gebruiken: uit, waarschuwen of blokkeren. Zie Pushes en de committerregel.
Wat het niet doet
- Het scant de geschiedenis niet met terugwerkende kracht. Is een inloggegeven gecommit voordat push-bescherming aanstond, dan blijft het gecommit. Gebruik een tool om de geschiedenis te herschrijven (de migratiehandleiding loopt dat met je door).
- Het vangt niet elke denkbare vorm van inloggegevens. Eigen regels per tenant dekken de gaten die voor jouw stack ertoe doen.
- Het draait niet bij
git push --forcevan een branch die fremforge al kent (de pre-receive-hook draait nog wel, maar vergelijkt met de nieuwe tip; een force-push die een gelekte commit vervangt door een schone, wordt toegestaan).