DEV Community

Hive80-lab
Hive80-lab

Posted on Originally published at hive80-lab.github.io

Your repo is the most valuable thing you own online. You left the defaults on.

Somewhere in your org right now there is a personal access token with repo scope, created eleven months ago, owned by a person who left in April.

The repo it can read is your product. That is not a hypothetical — it is the default state of every small team that has never done a repo security pass.

The good news: GitHub already ships the controls. No paid tools, no security engineer, no migration. Ninety minutes of settings most repos leave at default removes the worst half of the risk. Here's the pass, in the order I'd run it.

1. Count who can push to main — then cut it

Write access is the new admin. Anyone who can push to the default branch can edit the workflow files that hold your deploy credentials, or quietly change what your app logs. Open the org's People page and the repo's Collaborators list:

  • Org-level Base permissions: read makes read the default instead of a per-repo promise.
  • Push-to-main should be 2–4 named humans. Everyone else: read or triage.
  • Count the bots. If a token can push to main, it belongs in the same count as people. Name it, scope it, expire it.
  • Require 2FA for the org. One toggle removes the entire password-spray attack class. Give people a week to enroll, then let GitHub do the nagging.

2. Make main annoying to break

Branch protection is free and takes ten minutes (Settings → Branches):

  1. Require a PR before merging — on a two-person team the "one approval" is just the other person glancing at it, and that glance catches most Friday-shaped disasters.
  2. Block force pushes and deletions. A force push doesn't just rewrite history — it can silently revert a fix someone already shipped.
  3. Require status checks so the test suite (and later, the secret scan) becomes a property of the system instead of a habit.
  4. Add a CODEOWNERS file: three lines — who owns .github/workflows/, who owns deploy configs, who owns the code that touches customer data. Workflow edits are where code access becomes server access.

One rule that keeps the audit honest: protection rules that get disabled in an "emergency" get re-enabled and logged the same day. The emergency merge is fine; the missing follow-up is the defect.

3. Treat every committed secret as burned

The most common small-team breach isn't an exploit — it's a key committed once, in a throwaway branch, in March. Scanners harvest public repos within minutes, and tokens with repo scope read private repos too.

  • Turn on secret scanning + push protection (free on public repos). Push protection blocks the commit before it lands — cheapest control on this page, measured in prevented incidents per setup-hour.
  • Sweep history once with gitleaks or trufflehog. Every hit is a rotation job, not a rewrite job: revoke the key, and stop worrying about the old commits. Rotate first; clean history only for the repo you'll actually maintain.
  • Move secrets into Actions secrets or a secret manager and write the convention in the README: secrets live in the platform vault, never in files.
  • Audit personal access tokens (Settings → Developer settings): the months-old tokens with repo scope are the classic. Fine-grained, per-repo, expiring — and the ones nobody remembers creating get revoked. Org-level too: check tokens members issued to themselves.

4. Dependencies: three free controls

You will not audit hundreds of transitive packages. You need:

  1. Dependabot alerts + version updates — with a weekly 30-minute triage: high/critical first, and dismiss the noise with a written reason (that reason is audit evidence later).
  2. Dependency review on PRs — the malicious-package case shows up right in the diff as "added: some-package-you-never-heard-of", exactly where a reviewer notices.
  3. Lockfiles, committed — a supply-chain surprise should be a one-line lockfile diff, not a silent upgrade.

5. The CI is part of the attack surface

Workflows run with your secrets. The small-team hardening set:

  • Pin third-party actions to a full-length commit SHA, not a tag. Tags are moving targets; their maintainers' bad day becomes your build's bad day.
  • Set a default permissions: contents: read at the top of every workflow and grant more only where needed.
  • Require approval for first-time contributors' workflow runs — without it, a drive-by PR executes code in your CI with access to your environment.
  • Read your triggers once, slowly: pull_request_target checking out untrusted code with secrets present is the classic footgun.

6. The side doors nobody audits

  • Deploy keys (Settings → Deploy keys): one SSH key per forgotten server. Name the server each one belongs to; revoke the ones with no name.
  • Webhooks: each holds a secret that lets its receiver impersonate your repo's events. Old CI installs, deleted Slack channels. Verify, confirm TLS, rotate what's older than your memory of creating it.
  • GitHub App installs: every integration you clicked "install" on holds scoped, durable access. Does a linting app need read access to all repositories? Uninstall the trials; scope the keepers.

7. Offboarding, and the artifact that closes the loop

Remove org membership the same day access ends — but first list what they touched: personal forks, deploy keys they created, environments where their approval was required. Rotate the credentials that existed during their tenure. One hour, and the "they copied the token in February" question closes permanently.

Then, monthly (30 minutes): member list vs. team chart, new PATs and app installs, open Dependabot alerts, deploy keys and webhooks named and owned, audit log export filed. That export is the dated artifact that turns "we take access seriously" into something a customer or insurer can actually read.

The one-afternoon version, in order

  1. Enforce org 2FA
  2. Base permissions → read; audit the write list
  3. Protect main (PRs, no force push, status checks)
  4. Secret scanning + push protection
  5. Dependabot alerts
  6. Audit PATs, deploy keys, webhooks — revoke the unnamed
  7. Export the audit log

Ninety minutes, no paid tools — and the repo stops being the easiest door into the company.


I wrote the full version as a free page on our ops-notes site — including the CODEOWNERS setup, the environment-approval gate for production secrets, and the monthly minute-by-minute pass:

👉 GitHub Repository Security Checklist for Small Teams

If you want the fill-in-the-blanks version of the surrounding discipline, that's what the HIVE80lab kit is for:

Launch week: 30% off any paid kit with code HIVE-LAUNCH30 at checkout.

Top comments (0)