Repository navigation
[Vulnerability] github/github-mcp-server: Race Condition / Unauthorized Content Modification #91
Description
Potential Security Vulnerability Detected
Repository: github/github-mcp-server
Commit: 5a3c558
Author: Dylan Pulver
Date: 2026-09-01T13:05:10Z
Commit Message
fix(repos): give create_or_update_file callers a SHA they can actually get (#3131)
* fix(repos): give create_or_update_file callers a SHA they can actually get
The create_or_update_file tool description and both of its SHA errors told
the caller to run `git rev-parse <branch>:<path>`. The caller is an MCP
client talking to the GitHub API, and the same description tells it not to
use this tool for local file operations, so it has no working tree to run
that command against.
Point the description at get_file_contents instead, which returns the blob
SHA over the API. In the already-exists error the server has just fetched
the file, so return that SHA directly rather than asking for a round trip.
The stale-SHA error already interpolates the current SHA, so it only needed
the impossible instruction removed.
* fix(repos): stop disclosing the blob SHA when no sha was supplied
The already-exists path is reached only when the caller sent no sha, so
it has not read the file. Returning the current blob SHA there let it
overwrite content it never saw on the next call, which is the race the
SHA gate exists to prevent. Send the caller to get_file_contents for the
path and ref instead, so obtaining the SHA still requires reading the
file.
The stale-SHA path is unaffected: the caller did supply a sha, and that
message already reported the current SHA before this change. Only its
recovery step moved off git rev-parse, and it is now imperative rather
than conditional, since a stale SHA means the file definitely changed.
Assert the already-exists error does not contain the blob SHA so the
gate cannot be loosened again without a test failing.
* fix(repos): make SHA recovery guidance actionable
Map create_or_update_file branch arguments to get_file_contents ref arguments, identify where the requested path SHA is returned, and cover symlink, branch, and API error behavior.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Dylan Pulver <dylanpulver@users.noreply.github.com>
Co-authored-by: Sam Morrow <info@sam-morrow.com>
Co-authored-by: Sam Morrow <sammorrowdrums@github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Pull Request
PR: #3131 - fix(repos): give create_or_update_file callers a SHA they can actually get
Labels: None
Description:
Summary
create_or_update_file told its caller to run git rev-parse <branch>:<path> to get a blob SHA, which an MCP client has no way to do. This replaces that instruction with the SHA itself where the server has it, and with a pointer to get_file_contents where it does not.
Why
Fixes #3130
git rev-parse reads a local object database, and a client using this tool over the API has no clone. The instruction appears in both SHA error paths, so an agent hitting either is handed a re...
Analysis
Vulnerability Type: Race Condition / Unauthorized Content Modification
Severity: High
Description
The create_or_update_file tool had a race condition vulnerability where an MCP client could overwrite file content without providing the correct SHA when no SHA was supplied. The error message previously returned the current blob SHA, allowing an attacker to use this disclosed SHA to overwrite content they never read, bypassing the SHA validation gate designed to prevent blind overwrites. The patch removes the SHA from the error response and requires callers to fetch it through get_file_contents, eliminating the race condition window.
Affected Code
File already exists at %s. You must provide the current file's SHA when updating. Use git rev-parse %s:%s to get the blob SHA, then retry with the sha parameter. (previously returned currentSHA in error or description)
Proof of Concept
1. Client A calls create_or_update_file with no SHA to update docs/example.md. 2. Server checks file exists, returns error with current blob SHA (e.g., 'abc123'). 3. Client A (or attacker) immediately calls create_or_update_file again with sha='abc123' and malicious content before the actual file owner can read and update it. 4. The content is overwritten because the SHA was disclosed in the error message from step 2, allowing the attacker to bypass the intended read-before-write protection. After the patch, step 2 no longer returns the SHA, so step 3 fails unless the attacker independently fetches the file via get_file_contents.
This issue was automatically created by Vulnerability Spoiler Alert.
Detected at: 2026-10-06T08:38:59.431Z
Activity