access & permissions 29 October 2026

github is your identity surface

every developer has more access at your company than your most senior exec.

The companies, people and numbers in the scenarios below are illustrative composites of common situations. They are not real cases or measured results. Anything presented as data names its source.

A security lead at a 250-person software company pulled a report of every GitHub permission at the company in mid-2025. The report had several columns: user, repository, access level, teams, and installed apps. The report was several thousand rows.

Filtering for admin access at the organization level, the report showed twelve people. Seven were current employees. Three were former employees whose accounts had not been demoted. Two were contractors whose engagements had ended eighteen months earlier.

Filtering for repository-level admin access, the report showed a different picture. Every engineer had admin on at least the repositories they actively worked on. Many had admin on repositories they had touched once, years ago, and never returned to. The longest-tenured engineers had admin on dozens of repositories, including legacy ones nobody maintained anymore.

Filtering for installed GitHub Apps, the report showed 47 distinct applications. The security lead recognized about 15 of them. The rest had been installed at various points over the company’s history, often by individual developers authorizing apps they wanted to use. Each app had a set of permissions against the org’s repositories. Some had read-only. Several had read-write. A handful had administrative capabilities.

Filtering for webhooks, the report showed 200+ configured endpoints across repositories. Many pointed to URLs the security lead didn’t recognize, old CI systems that had been replaced, third-party integrations from vendors the company no longer used, personal servers belonging to ex-employees.

This is the state of GitHub at most software companies. The identity surface is large, tangled, and not governed by the same controls that apply to other systems in the company.

This essay is about that surface. Why GitHub is a special case in the identity landscape, what makes it so consequential, and why it deserves the same level of scrutiny as your CRM or your HRIS.

the repository is the crown jewel

For a software company, the code is the product. The code lives in GitHub (or GitLab, or equivalent). The repository access controls are the controls that govern who can read the product, who can modify the product, and who can deploy the product.

This is the highest-stakes access decision in a software company. Access to the customer database is serious. Access to customer records in Salesforce is serious. Access to the code is arguably more serious, because the code is the thing that generates everything else. Compromise of the code leads to downstream compromise of every system the code interacts with.

The conventional identity program focuses heavily on the CRM, the HRIS, the financial systems. These are the obvious sensitive systems. The code repository often gets less explicit attention, because it’s viewed as a developer tool rather than a system-of-record.

The result is that code repositories often have looser access controls, weaker review cadence, and less robust audit trails than the systems traditionally associated with sensitive data. A software company with a rigorous SOC 2 program may have comprehensive controls on Salesforce and much looser practical controls on GitHub, even though the codebase is more consequential for the company’s operation.

This asymmetry is worth naming explicitly. The identity surface of GitHub is as sensitive as, or more sensitive than, the identity surface of the CRM. It should be governed at the same level of rigor.

the doors into your code

  • organisation adminsincluding people who left or changed teams
  • team membershipsthe main way access is granted
  • outside collaboratorsadded per repository, outside teams
  • installed GitHub Appsmany installed years ago
  • personal access tokenstied to a person, used by scripts
  • webhookssending events to URLs nobody recognises

often still openusually handled

the developer workflow resists central control

The specific challenge with GitHub access is that developer workflows resist the kind of central control that applies to other systems.

In Salesforce, a typical user has a role with a specific permission set. The role is assigned by an admin. The permission set is defined by the admin. The user’s actions are bounded by the permission set.

In GitHub, developers expect to be able to fork, branch, pull, push, create repositories, add collaborators, and configure their own workflows. These are the daily operations of software development. Centralizing all of these actions under admin approval would slow the work to a crawl. So GitHub admin practices typically grant developers broad capabilities on the repositories they work on, with central control retained for org-level actions.

Broad capabilities at the repository level, accumulated across a developer’s tenure, produce the access creep pattern that this essay series describes. Every repository a developer has ever worked on is a repository they probably still have access to. The access persists unless someone explicitly removes it.

For a long-tenured developer, the access surface is the accumulated set of every project they’ve ever touched. Current projects. Old projects. Prototypes that got abandoned. Internal tools that are no longer maintained. Each of these contributes to the developer’s accessible repository set.

the team is the main access mechanism

GitHub’s primary mechanism for managing access is the team. Teams are collections of users. Teams have permission grants against repositories. A user’s access to a repository is determined by the teams they’re a member of and what permissions those teams have.

In a clean deployment, teams map to organizational structure. A product engineering team in the org becomes a GitHub team. The team has permissions on the repositories that team works on. Adding a developer to the team grants them access. Removing the developer revokes the access.

Real GitHub deployments at mid-market companies are never this clean. The teams include:

The teams that map to organizational structure.

The legacy teams from previous organizational structures that were never deleted.

The project-specific teams that were created for specific initiatives and outlived them.

The permission-specific teams that were created to grant a specific capability (like “can merge to main”) and have accumulated members over time.

The shadow teams that someone created for their own purposes and have been co-opted by other people.

A long-tenured developer is typically in a dozen or more teams, of which several might be legitimately current and the rest are residual. The residual team memberships grant access to repositories the developer hasn’t touched in years.

Cleaning up teams requires ongoing attention. Most organizations don’t give it. The team structure grows monotonically, and developer access grows with it.

the GitHub Apps ecosystem

GitHub Apps are a specific category of third-party integration with their own permission model. An App is installed on an organization or on specific repositories, with a set of permissions (read access to code, read access to metadata, write access to checks, write access to pull requests, etc.).

App installations are the third-party access surface of GitHub, equivalent to OAuth grants in other systems. Each installation gives an external application standing access to the org’s data.

The installations accumulate. A typical pattern: a developer wants to try a new security scanning tool. The tool is available as a GitHub App. The developer installs it on one repository. The app now has access. The developer eventually stops using the tool. The installation persists.

Over years of accumulated installations, the org has dozens of apps installed, most of which are no longer actively used, some of which are from vendors that have gone out of business or been acquired, a few of which have permissions that would surprise the current admin team.

Reviewing GitHub App installations is rarely part of routine identity hygiene. The installations are tucked in the org settings, reviewed at install time and then forgotten. A periodic audit, quarterly or annually, would catch the accumulated sprawl.

The audit is mechanical. Open org settings, go to installed GitHub Apps, review each one. For each app, ask: are we still using this? Who owns this? What permissions does it have? Is the vendor still in business? Is there a newer alternative?

Uninstall the ones that fail any of these checks.

the personal access tokens

Personal Access Tokens (PATs) are user-scoped credentials that can be used for API access or Git operations. They’re long-lived by default, they bypass SSO, and they can be used from any device.

A developer generates a PAT for an automation script. The script uses the PAT to commit code, create pull requests, or interact with the API. The PAT is stored in the script’s configuration, typically as an environment variable or a secret in the CI system.

The PAT inherits the developer’s permissions. If the developer has admin on a repository, the PAT does too. If the developer has write access to every repository in the org, the PAT has that too.

When the developer leaves the company, their account is deprovisioned. The PATs they generated are invalidated as a side effect of the account being disabled. In theory. In practice, the invalidation depends on how the deprovisioning was done. If the account was deleted, PATs go with it. If the account was only disabled, PATs may still be valid until explicit revocation or expiration.

The more common issue: the PAT that the developer stored somewhere that persists beyond their employment. A PAT copied to a personal laptop, a PAT shared in a Slack DM, a PAT committed to a repository (intentionally or accidentally). If the PAT is still valid and in the hands of someone who shouldn’t have it, the exposure is the full set of permissions the issuing developer held.

GitHub has added some mitigations. Fine-grained PATs with limited scopes. PAT expiration enforcement. SSO-required PATs for enterprise plans. These help for new deployments. Most existing PATs predate the mitigations.

Auditing PATs in an enterprise GitHub deployment is supported. The audit reveals PATs that are old, broadly scoped, or attached to inactive users. Rotating or revoking them is the cleanup.

webhooks are unauthenticated egress

GitHub webhooks are the mechanism by which GitHub notifies external systems of events. A push happens, and a webhook fires a POST to a configured URL with the event details.

Webhooks are a specific category of exposure. They configure outbound communication from GitHub to arbitrary URLs. If an attacker can configure a webhook, they can exfiltrate data about repositories, pull requests, and other events to a URL of their choice.

The permission to configure webhooks is typically admin-level on the repository. An attacker who compromises an admin account, even temporarily, can configure webhooks that will continue to exfiltrate data after the account is detected and cleaned up.

Webhook configuration audits are rare. Most GitHub admins don’t routinely review the webhook list at the repository or org level. The webhooks accumulate, point at various external services, and some of them point at services nobody can currently identify.

The specific failure mode: a repository has a webhook configured to post to a CI system’s URL. The CI system was replaced three years ago. The URL is now owned by someone else, or is serving a different service, or is simply dead. The webhook continues to fire, sending commit data and pull request metadata to wherever the URL now resolves.

Auditing webhooks requires reviewing each repository’s webhook configuration. For large orgs, this is a lot of configuration to review. The tooling for this exists but is not always used. Running the review at least annually catches the worst of the sprawl.

the branch protection gap

Branch protection rules are GitHub’s mechanism for constraining what can happen on specific branches. A protected main branch might require pull request review, status checks, and approvals from code owners before merging.

Branch protection is a security control. Without it, anyone with write access can push directly to main. With it, the push path requires review.

Most mature engineering orgs have branch protection configured on main branches of important repositories. The configuration is not uniform. Some repositories are protected. Some are not. Some have strong protection (multiple required reviewers, code owner approval, linear history enforcement). Some have weak protection (just a single reviewer check).

A comprehensive GitHub identity audit includes reviewing branch protection configuration. For every repository with any sensitivity, production code, infrastructure as code, security tooling, anything deployed to production, the branch protection should be appropriate to the sensitivity.

Gaps are common. New repositories don’t automatically get branch protection configured. Repositories inherited from acquisitions often have no protection. Legacy repositories from before the company’s current practices have whatever was configured years ago, which may be nothing.

the exercise

For a software company, here is the GitHub identity audit worth running.

Pull every user in the org. For each user, pull their team memberships and their repository access. Call this the User-Access list.

Filter for users with admin access at the org level. Review each one. Every admin should be a current, named, justified admin. Anyone who doesn’t meet that standard should be demoted or removed.

Filter for users with access to each high-sensitivity repository. Review each user’s justification. Anyone without a current justification should be removed.

Pull the installed GitHub Apps list. Review each one. Uninstall anything not in active use.

Pull the webhook configurations across all repositories. Review each one. Remove anything pointing at URLs you can’t identify.

Pull the PATs issued in the org (enterprise plans support this; non-enterprise plans require indirect methods). Review for old, broadly-scoped, or user-inactive PATs. Rotate or revoke.

Pull the branch protection configurations. Compare to repository sensitivity. Upgrade any gaps.

This is a lot of work for the first pass. The subsequent quarterly passes are much smaller. The goal is to establish a baseline clean state and maintain it with periodic attention.

GitHub is the identity system you’ve been treating as a developer tool. It’s a first-class identity system, with all the complexity of your CRM and your HRIS, plus the specific developer-workflow complications that make it harder to govern.

Give it the same attention you give Salesforce. It’s holding something at least as valuable.

access creep · every two weeks

One mechanism, one practical step.