Source code leaves through authenticated Git operations. A stolen personal access token or a departing engineer’s cloned repository defeats every perimeter control you own, because the request arrives signed, scoped, and indistinguishable from routine work. The defensible program is identity-lifecycle control plus Git-behavior monitoring, executed in five ordered steps. Token hygiene comes first because it is the highest-leverage, lowest-friction fix available to any team running GitHub, GitLab, or Bitbucket.
Quick Take
- Step 1: Token governance: retire classic PATs and perpetual SSH keys for short-lived, fine-grained tokens scoped to single repositories, backed by phishing-resistant MFA.
- Step 2: Behavior monitoring: alert on mass clones, geographic IP spikes, and off-hours downloads; treat this as detective evidence that only pays off when paired with Step 1.
- Step 3: Exfiltration controls: rate limits and anomaly detection catch fast API scraping; offboarding automation, DLP, and endpoint signals catch low-and-slow insider theft.
- Step 4: Supply chain and secrets: pre-commit hooks, server-side push protection, and pinned CI actions keep credentials out of commit history.
- Step 5: Offboarding: SCIM deprovisioning from Okta or Entra ID kills SCM access, forks, and sessions the moment an account is disabled.
Prerequisites Before You Start
Prerequisites
- Organization-owner or platform-admin rights on your SCM (GitHub org owner, GitLab group owner, or Bitbucket workspace admin).
- An identity provider (Okta, Entra ID, or equivalent) with SSO/SAML configured for the SCM and SCIM provisioning available on your plan.
- MFA enrollment enforced for every account with write access, with hardware keys or passkeys preferred over SMS.
- A current inventory of personal access tokens, deploy keys, SSH keys, and OAuth apps with repository scope.
- Read access to CI/CD configuration files across active repositories.
Info
Smaller organizations without an IdP can approximate Steps 1 and 5 with token expiration policies and a manual revocation checklist. Branch protection and MFA should be enabled regardless of team size; small teams are targeted precisely because they skip these controls.
How to Execute the Five-Step Git Hardening Protocol
Run the steps in order. Each one reduces the blast radius of the next, and each ends with an observable state you can confirm before moving on.
- Retire long-lived credentials for short-lived, scoped tokens.Audit every personal access token, deploy key, and SSH key in the organization. Revoke tokens with no expiration, admin scope, or access to repositories the owner no longer touches. Replace them with fine-grained tokens limited to specific repositories and permissions, or with just-in-time SSH certificates issued by a certificate authority for per-session authorization, a pattern that replaces long-lived keys and PATs with per-session credentials.Classic PATs are over-permissioned by default and rarely rotated, which makes them among the most frequent vectors for repository compromise. Where your platform supports it, prefer OIDC federation for CI workloads over stored cloud keys, and require phishing-resistant MFA for every account with write access.
When you finish, the token inventory should show only scoped, expiring credentials, and the MFA enforcement policy should list every write-capable account as compliant.
- Turn on Git behavior monitoring and anomaly alerting.Enable audit logging on the SCM and stream it to a system that can alert. Configure detections for mass
git cloneand fetch activity, sudden geographic IP changes for a single identity, off-hours repository downloads, new deploy keys or webhooks, and permission escalations.Monitoring is detective, not preventive. On its own it produces post-incident evidence; paired with Step 1 it shortens the window between a stolen token being used and that token being revoked. Tune alerts toward risky destinations and anomalous volume so legitimate pushes and CI operations do not drown the signal.Confirm success by triggering a test alert from a non-corporate IP and verifying it lands in your queue with the correct identity and repository context.
- Separate fast and slow exfiltration controls.Fast exfiltration is automated API scraping from a compromised credential: hundreds of clones in minutes, from a handful of IPs, at machine speed. Slow exfiltration is a departing engineer pulling repositories incrementally over weeks, often from a sanctioned laptop during working hours. They need different controls, and a program that only addresses one leaves the other open.For fast threats, apply clone rate limits, anomaly detection on volume and velocity, and immediate token revocation on alert. For slow threats, rely on offboarding automation, DLP on endpoints and cloud destinations, and signals such as bulk zipping, external drive copies, and unusual terminal activity before a departure date. Teams building out the detection side of this split can review practical approaches to prevent source code exfiltration across both threat profiles.
Verify coverage by mapping each alert rule to a threat type. Every fast-path rule should name the volume threshold that triggers it, and every slow-path signal should be tied to an owner in HR, IT, or security.
- Isolate secrets and lock down the supply chain.Install pre-commit hooks that scan staged changes for secret patterns and block the commit locally. Enable server-side push protection so anything that slips past the hook is caught at push time, and run a full-history scan to find credentials already sitting in old commits. Microsoft’s own guidance on securing source code with GitHub Advanced Security documents push protection and historical secret scanning as the enforcement layer behind local hooks.On protected branches, require pull requests with at least one approving review, passing status checks, signed commits, and no force pushes. Use CODEOWNERS to require security review on CI configuration and deployment scripts. Pin CI actions to full commit SHAs rather than mutable tags, and scope pipeline credentials to the minimum each job needs.
Confirm the controls by attempting a test commit containing a dummy credential pattern; the hook should reject it locally, and a bypass attempt should be blocked by push protection at the server.
- Automate offboarding through your identity provider.Connect the SCM to Okta, Entra ID, or your equivalent IdP with SCIM provisioning enabled. When an account is disabled in the IdP, SCIM should remove SCM membership, revoke active sessions, and drop access to organization-owned forks and private repositories.Offboarding gaps are where most programs fail silently: access retained after a notice period, contractor accounts left active past contract end, role changes that never trigger a permission review. Align HR, IT, and security on a scenario-based workflow so termination, resignation, and role change each fire the correct deprovisioning event.
Verify by running a deprovisioning test on a staging account and confirming the SCM shows no active session, no organization membership, and no repository access within minutes of the IdP disable.
Fast vs. Slow Exfiltration: Which Control Catches Which Threat
| Threat profile | Typical signal | Primary control | Supporting control |
|---|---|---|---|
| Fast: automated API scraping | Hundreds of clones in minutes from a small IP set | Clone rate limiting and volume anomaly detection | Immediate token revocation on alert |
| Fast: compromised developer account | Authentication from an unusual geography | Geographic IP anomaly alerting | Phishing-resistant MFA and short-lived tokens |
| Slow: departing insider | Incremental pulls over weeks, bulk zipping, external drive copies | Offboarding automation via SCIM | Endpoint DLP and pre-departure behavior signals |
| Slow: contractor over-retention | Access retained past contract end | IdP-driven deprovisioning | Quarterly access reviews |
| Both | Audit-log trail of who accessed what and when | Audit logging with multi-month retention | Alerting on new deploy keys, webhooks, and permission escalations |
Verification Checklist
Verify the result
- Token inventory shows only scoped, expiring credentials, and MFA enforcement lists every write-capable account as compliant.
- A test alert from a non-corporate IP arrives in your monitoring queue with correct identity and repository context.
- Every fast-path alert rule names a volume threshold, and every slow-path signal has a named owner.
- A test commit containing a dummy credential is rejected by the pre-commit hook and blocked by push protection on bypass.
- Protected branches reject direct pushes, force pushes, and unsigned commits.
- A staging account disabled in the IdP loses SCM membership, sessions, and repository access within minutes.
- Audit logs are retained for a multi-month window and streamed to a system that can alert.
Recovery When Something Goes Wrong
A secret was committed and pushed before push protection caught it
Treat the credential as compromised the moment it lands. Rotate it first, then remove it from history with git filter-repo or BFG Repo-Cleaner. Removal without rotation leaves a burned credential in every existing clone.
Developers are bypassing pre-commit hooks with --no-verify
Local hooks are advisory. Rely on server-side push protection and CI scanning as the enforcement layer, and treat repeated bypasses as a training signal rather than a policy failure. The server check cannot be skipped.
Branch protection is blocking legitimate hotfixes
Phase the rollout. Start with the default branch on your highest-value repositories, then extend to release branches. Add a documented break-glass path with post-hoc review instead of disabling protection under deadline pressure.
SCIM deprovisioning removed the wrong account or missed a contractor
Check the IdP group-to-SCM-role mapping. Contractors are often provisioned outside the main lifecycle group, so they escape automated deprovisioning. Run a quarterly reconciliation between IdP active accounts and SCM members to catch the gap.
Monitoring is generating alert fatigue on legitimate CI traffic
Whitelist sanctioned CI service accounts and known build IPs, then tune thresholds against your actual baseline. Alert on risky destinations and anomalous volume rather than every clone command. A noisy monitor gets muted, and a muted monitor catches nothing.
Rollout Order and the Highest-Risk Gap
If you can only do one thing this quarter, do Step 1. Stale tokens and retained offboarding access are the two gaps that turn a routine credential leak into a full repository exfiltration, and both are fixable without touching developer workflow. Layer Step 5 immediately after, because offboarding gaps persist silently for months and no alert will tell you an account should have been disabled.
Steps 2 and 4 come next. Monitoring without token hygiene only documents the theft after it happens, and branch protection plus secret scanning are cheap, high-value controls that phase in cleanly on your highest-value repositories first. Step 3 is the refinement layer: once you have clean identities and working alerts, you can tune the fast and slow paths separately and stop guessing which control is supposed to catch which threat.
Warning
Do not respond to a suspected insider incident by banning local Git or blocking remote IDEs. Those measures destroy developer productivity and push exfiltration to personal devices where you have no visibility. Match the response to the offender and the offense: coaching for first-time mistakes, containment and formal investigation for confirmed exfiltration.
The five steps form one program, and the order matters less than the completeness. Teams that retire stale tokens, automate offboarding, and watch Git behavior catch theft while it is still a credential event. Teams that skip those steps discover the gap only after a repository tree has already been cloned.
💬 Comments