How to stop AI agents from pushing to protected branches through the GitHub MCP server
Use GitHub-native controls first: least-privilege tokens, rulesets, required pull request reviews, and restricted toolsets or read-only mode. Then enforce policy on each MCP tool call at runtime, so branch-write actions are allowed, blocked or escalated for human approval, and every decision leaves evidence.
Add runtime policy enforcement at the MCP tool-call layer
- Agent issues an MCP tool call
- Policy evaluates the tool, repository, branch and arguments
- Decision: allow, block, or escalate for human approval
- Allowed calls reach the GitHub MCP server under the scoped credential
- Decision and applying policy are written as evidence
Configure the GitHub-native controls
1. Give the agent its own narrow credential
Use a dedicated token or app identity limited to the repositories the task needs, with the fewest write permissions that still work. Avoid reusing a developer or administrator token.
2. Start read-only
Where the server supports it, run in read-only mode, or enable only the toolsets the task requires. Add write tools by exception, per use case.
3. Protect branches with rulesets
Require pull requests, required approvals and status checks on default and release branches. Block force pushes and deletions.
4. Remove bypass for the agent
Confirm the agent's identity holds no bypass permission and no administrator role. Review bypass lists and token owners on a schedule.
5. Keep approval human
Require reviews from someone other than the author, so an agent-opened pull request cannot be approved or merged by the same identity.
6. Test the deny paths
With the agent credential, attempt a direct push, a merge and a force push on a protected branch. Record the results.
Map write-capable tools to branch-protection risk
The GitHub MCP server gives an agent a set of tools, and the agent calls them using a single credential, usually a personal access token or an app token. GitHub evaluates the credential and the repository. It does not evaluate what the agent was trying to do. Start by listing the write-capable operations your deployment exposes and asking what each one can reach.
This matters beyond direct pushes. An agent that cannot push to a protected branch may still create a branch, commit files to it and open a pull request. If it can also merge, or if its identity can bypass review, the protection is only as strong as the weakest step in that chain. A NIST presentation on agentic security also names GitHub MCP tool descriptions as an agentic supply-chain risk, because an agent may treat them as workflow guidance and take actions nobody intended.
- Create or update file contents: Risk: commits land on whichever branch the call names. Depends on the protection rule and whether the identity can bypass it.
- Create a branch: Risk: a lower-risk step that gives the agent a place to commit. Consider limiting by branch name pattern.
- Push multiple files in one call: Risk: a larger change set from a single instruction, harder to review.
- Open a pull request: Risk: starts a review path. Acceptable if required reviews are enforced and the agent cannot approve.
- Merge a pull request: Risk: the step that moves code into a protected branch. Highest priority to remove or gate.
- Read-only tools: Risk: low for branch writes. Read content can still carry instructions that steer later calls.
Where native controls stop
Native controls are necessary and should be your baseline. Their limits are structural. Branch protection and rulesets apply to a repository and a branch. Token scoping applies to an identity. Neither sees the individual MCP tool call, the instruction that produced it, or the task the agent was meant to perform.
That leaves several gaps. A token scoped for legitimate write work can still write to branches you did not intend if those branches are not covered by a rule. Anything with bypass permissions or administrator rights sits outside the rules by design. Scoping is also coarse: a token that can open pull requests for one purpose can usually open them for any purpose, and the agent decides which. If an agent can create branches, commit files and open pull requests, each call is individually valid under GitHub's model, even when the sequence is not what the owner wanted.
There is also a record-keeping gap. Repository history shows what was committed. It does not show which calls the agent attempted and which were refused, or which policy applied at the time. Review after the fact also cannot undo a change that has already merged.
Retain evidence of what the agent was allowed to do and did
Security teams need to answer two questions afterward: what was this agent permitted to do, and what did it do? Repository history answers only part of the second. NCCoE material points to accountability for the actions of automated systems and visibility into actions taken, which supports keeping a complete record rather than relying on commit history.
For branch-write actions, retain for each tool call: the agent and credential identity, the tool and its arguments, the target repository and branch, the decision (allowed, blocked or escalated), the policy and version that applied, and, for escalations, who approved or denied and when. Keep blocked attempts as well as allowed ones, since a pattern of blocked writes is often the first sign that an agent is being steered. Set retention to match your change-management and audit obligations.
You can then pair this with the native record. Rulesets and review history show how changes were approved in GitHub, and the tool-call record shows how the agent reached them. Map the records to your own change-management controls with your auditors rather than assuming a framework mapping.
Where Trussed fits
Trussed enforces policy in the execution path across agents, tools and MCP servers, including individual tool calls. For the GitHub MCP server, that means branch-write calls can be allowed, redacted, blocked or escalated for human approval, with enforcement at runtime rather than after the fact. Trussed also provides code provenance, covering the origin, licence and security context of code, and generates continuous audit-ready evidence from enforcement, mapped to frameworks including NIST.
Trussed deploys self-managed in the customer cloud, with configurable retention and data residency. It is built for regulated enterprises that need to show an auditor what their AI was allowed to do and what it did. It complements GitHub's own controls and does not replace them.
Layers that keep agent writes off protected branches
Label: Credential
Description: Narrow token or app permissions, scoped to specific repositories.
Label: Tool surface
Description: Restricted toolsets or read-only mode on the MCP server.
Label: Repository rules
Description: Rulesets and required reviews on protected branches.
Label: Runtime policy
Description: Allow, block or escalate each tool call before it executes.
Label: Evidence
Description: A record of each attempt, decision and applying policy.
See tool-call enforcement for GitHub MCP in practice
Walk through how branch-write calls are allowed, blocked or escalated, and what evidence each decision produces.
Request a Demo