Blocking force pushes and branch deletion through the GitHub MCP server
Block force pushes and branch deletion in layers. Keep GitHub branch protection and rulesets as the baseline, issue agents least-privilege credentials, expose only the tools a task needs, and enforce policy on each MCP tool call before it executes. Each layer covers gaps the others leave, and each decision at the tool-call layer should produce a record you can show an auditor.
Verify enforcement and capture evidence
- Ask the agent to delete a protected branch and confirm the call is blocked or escalated before it reaches GitHub.
- Ask the agent to rewrite history on a protected branch and confirm the same outcome.
- Repeat both against a repository with no GitHub protection to confirm the tool-call layer holds on its own.
- Confirm an approved escalation executes once and an unapproved one does not.
- Confirm each decision record carries the tool name, arguments, decision, matching policy, agent identity, timestamp and approver where applicable. These fields are a practical suggestion, not a formal schema.
- Confirm records are retained in a store you control for the period your auditors expect.
What makes a tool call destructive
An MCP server is a program that exposes tools, resources and prompts through the protocol. When an AI coding assistant connects to the GitHub MCP server, every write-capable tool becomes something the model can invoke. A force push rewrites a branch so that it points to a commit that is not a descendant of the previous one, which can discard commit history. A branch deletion removes the ref itself. Both are hard to reverse and, without a decision record, hard to attribute to a specific agent session.
Classify tools by effect, not by name. Any tool that updates a ref, removes a ref, or writes commits to a branch belongs in your review set, along with the parameters that choose the target branch or change how the update is applied. Inspect the arguments as well as the tool name, because the same tool can be harmless with one argument set and destructive with another.
Do not rely on tool descriptions or annotations to tell you what is safe. Annotations are hints, not enforcement, and detecting a metadata change does not detect a change in server behavior behind an unchanged definition. Re-review the server whenever its tool definitions change.
Write access to source-code management is treated as high risk in the NIST SP 800-204D initial public draft, and OWASP's DSOMM lists blocking force pushes as an activity under Build and Deployment at level 3. Together they make this a reasonable control to formalize.
Native GitHub controls are the baseline, not the whole answer
Branch protection rules and rulesets apply at the repository or organization layer. They are the right place to state that protected branches cannot be force pushed or deleted, and they should stay in place whether or not an agent is involved. They protect the repository regardless of which client sends the request.
They also have limits that matter for agents. They only protect branches they are configured to cover, so a repository without a rule has no protection. They can be bypassed by credentials that hold administrative rights or a bypass permission, and an agent holding such a credential inherits that bypass. They say nothing about which tool the agent chose, what arguments it sent, or whether a human approved the action.
The same applies to credentials. A NIST scenario describes a developer assistant holding a high-privilege GitHub token to manage repository settings, so a low-privilege agent becomes a confused deputy performing high-risk actions. Token permissions set the ceiling for every tool call, so scope them to the repositories and operations the agent's task requires.
Where runtime policy on tool calls adds a control
GitHub-native controls and MCP-level controls do different jobs. GitHub decides whether a request against a ref is permitted. A policy at the MCP layer decides whether the agent is allowed to make the call at all, and it can do so before any request reaches GitHub. It can also respond in more ways than a refusal: a call can be allowed, blocked, or held for a person to approve.
OWASP guidance supports this placement. Authorization should be enforced in the execution component, outside the agent's context, and enforcement has to sit at points the agent process cannot touch. A prompt instruction such as "never force push" is inside the agent's context and can be overridden by injected content or by the model's own reasoning. A check in the execution path cannot.
Trussed enforces policy in the execution path across agents, tools, MCP servers and coding assistants. Its actions include allow, block, and escalate for human approval, applied to individual tool calls. For this use case, a policy would treat calls that delete a branch or rewrite a ref as block or escalate, and permit read operations and ordinary commits to feature branches. Enforcement is at runtime, not reviewed after the fact, and it generates audit-ready evidence as a product of each decision.
The tradeoff is operational. Escalation adds a human to the path, so reserve it for operations where a person's judgment is worth the delay, and block outright anything that no workflow should ever perform.
Evidence and operating the control
Treat each decision as evidence, not as a log line to search after an incident. A blocked force push is useful proof that a control operated, and an allowed read is part of the same record of what the agent was permitted to do. Trussed generates audit-ready evidence continuously from enforcement and supports self-managed deployment in the customer cloud, with configurable retention and data residency.
Keep the operating model simple. Review the tool inventory when the MCP server's definitions change, review policy when a new repository class comes into scope, and sample the decision records on a schedule. If agents routinely trigger escalations for the same operation, change the workflow or the credential rather than approving the same request repeatedly.
Four layers between an agent and your refs
GitHub-native protections
Branch protection rules and rulesets on the repository or organization.
Least-privilege credentials
Token or app permissions that set the ceiling for any tool call.
MCP tool configuration
Expose only the tools a task needs.
Runtime policy on tool calls
Allow, block, or escalate before execution, with a recorded decision.
Put a decision point in front of destructive tool calls
See how Trussed enforces policy on MCP tool calls in the execution path and produces audit-ready evidence for each decision.
Explore Agent and Tool-Call Enforcement