← MCP server and skill grades

github-mcp-server

github/github-mcp-server

C
Type
MCP server
Scanned
Oct 29, 2026
Version
f2a07cd13243
Files read
594

The GitHub MCP Server connects AI assistants to GitHub so they can read and manage repositories, issues, pull requests, workflows, and security alerts. The biggest risk is that malicious instructions hidden in untrusted GitHub content could trick the AI into exposing private data, making unauthorized changes, or using unescaped tool inputs to call unintended GitHub API endpoints with your credentials.

What it can reach

Network
Connects to GitHub API, raw content, upload, and OAuth endpoints (on github.com or GitHub Enterprise), and can listen on local ports for HTTP server mode or OAuth login callbacks.
Secrets
Reads GitHub Personal Access Tokens, OAuth credentials, GitHub App private keys, and encryption keys from environment variables, files, or HTTP headers.
Files
Reads optional local configuration files and GitHub App private key files, and writes optional log and translation export files.
Browser
Opens the system default web browser on your computer during interactive OAuth login.

Findings

1 high1 medium4 low
  1. HighREST API path traversal via unescaped owner and repo tool arguments

    pkg/github/code_quality.go:66

    Multiple tool handlers—including get_code_quality_finding in pkg/github/code_quality.go, find_duplicate in pkg/github/find_duplicate.go, and issue handlers in pkg/github/issues.go and pkg/github/issues_granular.go—interpolate owner and repo directly into fmt.Sprintf("repos/%s/%s/...", ...) before calling client.NewRequest. Because go-github resolves the path with BaseURL.Parse, an attacker supplying .. and # via prompt injection (for example, repo = "../../repos/org/private-repo/secret-scanning/alerts/1#") can traverse to arbitrary GitHub REST API endpoints using the user's token. In get_code_quality_finding, any JSON object returned by the target endpoint is marshaled back to the caller, bypassing --tools/--toolsets restrictions, dynamic OAuth scope challenges, and Mcp-Param-* proxy routing.

    Fix: Validate that owner and repo do not contain path separators, .., query, or fragment characters, and escape path segments with url.PathEscape (as done in pkg/github/rulesets.go and pkg/github/custom_properties.go).

  2. MediumUnbounded and uncancellable HTTP log download in downloadLogContent

    pkg/github/actions.go:167

    When get_job_logs is called with return_content=true, downloadLogContent downloads the job log URL using http.Get(logURL) on http.DefaultClient. It does not bind the request to the caller's ctx, sets no HTTP timeout, and streams the entire response body until EOF (only keeping a ring buffer of lines in memory). A stalled endpoint or multi-gigabyte workflow log can tie up server resources indefinitely even after the MCP request is cancelled.

    Fix: Create the request with http.NewRequestWithContext(ctx, http.MethodGet, logURL, nil), use an http.Client with a reasonable timeout, and cap the total number of bytes read from the response body.

  3. LowHTTP server mode binds to all network interfaces by default

    cmd/github-mcp-server/main.go:272

    When running github-mcp-server http, the --listen-host flag defaults to an empty string, which causes resolveListenAddress in pkg/http/server.go to bind to :8082 on all network interfaces (0.0.0.0 / ::). Although requests require a bearer token in the Authorization header, binding to all interfaces by default unnecessarily exposes the local HTTP server to the network.

    Fix: Default --listen-host to 127.0.0.1 and require an explicit flag (such as --listen-host 0.0.0.0) to bind to all interfaces.

  4. LowMCP App UI openLink bypasses host denial and does not validate URL schemes

    ui/src/hooks/useMcpApp.ts:119

    When an MCP App UI component calls openLink(url) and the MCP host rejects the request (result?.isError, for example due to a blocked domain or user cancellation), openLink ignores the host's decision and opens the URL anyway via window.open. In addition, untrusted profile links such as d.blog in ui/src/apps/get-me/App.tsx are rendered into <Link href={d.blog}> and passed to openLink without verifying that the URL uses http: or https:.

    Fix: Validate that external URLs use https: or http: before rendering or opening them, and do not fall back to window.open when app.openLink returns an explicit host denial.

  5. LowCommand injection when parsing untrusted logs in developer script script/prettyprint-log

    script/prettyprint-log:74

    The developer utility script/prettyprint-log extracts JSON payloads from log files and interpolates them into a double-quoted echo -e "..." command that is piped to bash. If a log file contains untrusted GitHub issue or PR text with shell command substitutions ($(...) or backticks), running this script on the log file will execute arbitrary shell commands.

    Fix: Avoid piping log content into bash; use jq -r or printf '%b' without invoking a subshell to unescape the JSON string.

  6. LowOverly permissive Content Security Policy in MCP App UI templates

    ui/src/apps/get-me/index.html:6

    The get-me MCP App UI defines a Content Security Policy that allows 'unsafe-eval' and unrestricted outbound connections via 'connect-src *', while the other UI entrypoints (issue-write, pr-edit, and pr-write) omit a Content Security Policy altogether. Because these UI views render untrusted GitHub content, permitting eval and arbitrary network connections weakens defense-in-depth if a rendering flaw is introduced.

    Fix: Remove 'unsafe-eval' and restrict 'connect-src' to 'none' (since MCP Apps communicate with the host over postMessage), and apply the policy across all UI app index.html templates.