> For the complete documentation index, see [llms.txt](https://docs.forestall.io/forestall/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.forestall.io/forestall/edges/github/gh_maintainer.md).

# GH\_MAINTAINER

## Summary

|                              |                        |
| ---------------------------- | ---------------------- |
| **Forestall ACL Alias**      | GH\_MAINTAINER         |
| **Edge Type**                | Attack Path            |
| **Affected Object Types**    | GitHub Teams           |
| **Exploitation Certainty**   | Certain                |
| **GitHub Role / Permission** | Team `maintainer` role |

## Description

`GH_MAINTAINER` represents that a user holds the **maintainer** role on a GitHub team. A team maintainer can manage the team without being an organization owner:

* Add and remove team members.
* Promote other members to maintainer.
* Edit team settings (name, description, visibility) and manage the team's repository access requests.
* Create and manage nested child teams.

This is a traversable **attack path** because controlling a maintainer means controlling the team's membership. An attacker who compromises a maintainer can add an attacker-controlled account to the team, and that account then inherits **everything the team can reach** — every repository granted to the team via `GH_HAS_ACCESS`, and the access of any nested child teams.

In effect, a maintainer indirectly holds all of the team's access, plus the ability to hand that access to anyone. Plain membership (no management rights) is modelled separately by `GH_IN_TEAM`.

## Identification

### GitHub Web Interface

1. Open the organization → **Teams** → select the team.
2. Open the **Members** tab. Each member's role is shown; filter or look for **Maintainer**.

### GitHub CLI

List the maintainers of a team:

```bash
gh api "orgs/{org}/teams/{team_slug}/members?role=maintainer" --paginate \
  --jq '.[].login'
```

Check a specific user's role in a team:

```bash
gh api "orgs/{org}/teams/{team_slug}/memberships/{username}" --jq '.role'
```

## Exploitation

A maintainer does not need any further privilege to weaponize the team — managing membership *is* the capability:

1. **Add an attacker-controlled account to the team.** The added account immediately inherits every repository the team can access.

   ```bash
   gh api --method PUT "orgs/{org}/teams/{team_slug}/memberships/{attacker}" -f role=member
   ```
2. **Reach the team's repositories.** Any repository the team holds `write`/`maintain`/`admin` on is now reachable by the attacker — enabling direct pushes, workflow tampering, or full repo control depending on the team's permission.
3. **Establish persistence.** Promote the attacker account to maintainer so the foothold survives, or quietly keep it as a member among many.

   ```bash
   gh api --method PUT "orgs/{org}/teams/{team_slug}/memberships/{attacker}" -f role=maintainer
   ```
4. **Pivot through nested teams.** If the team has child teams, the attacker can manage those as well, widening the blast radius.

## Mitigation

1. **Minimize team maintainers.** Keep the maintainer role to the few people who genuinely administer the team; everyone else should be a plain member.
2. **Review maintainers on privileged teams.** Treat maintainers of teams that hold `admin`/`write` on sensitive repositories as elevated access and audit them regularly.
3. **Prefer organization-level management for sensitive changes.** Where possible, route membership changes through an approved process rather than leaving them to individual maintainers.
4. **Require 2FA for maintainers.** A maintainer account without 2FA is a high-value target — enforce two-factor org-wide (see `FS6011`).

## Detection

| Event                     | Description                         |
| ------------------------- | ----------------------------------- |
| `team.add_member`         | A user was added to the team        |
| `team.remove_member`      | A user was removed from the team    |
| `team.promote_maintainer` | A member was promoted to maintainer |
| `team.demote_maintainer`  | A maintainer was demoted to member  |

Alert on members being added to privileged teams and on promotions to maintainer, especially when performed outside an approved change process. An unexpected actor adding an account to a team that holds sensitive repository access is a strong indicator of compromise.

## References

* <https://docs.github.com/en/organizations/organizing-members-into-teams/managing-team-members-in-your-organization>
* <https://docs.github.com/en/rest/teams/members#list-team-members>
