Git Issuer Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Git Issuer Mcp (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
An MCP (Model Context Protocol) server that enables AI agents to create GitHub issues on explicitly allow-listed repositories. It uses GitHub App authentication so the agent never touches tokens directly, and enforces input validation, rate limiting, and repository-level access control.
AI Agent → MCP Server (stdio) → GitHub App Auth → GitHub REST API → RepositoryThe server exposes a single create_issue tool over MCP's stdio transport. When an agent calls it, the request flows through:
ALLOWED_REPOS are acceptedAll errors are returned as structured JSON with a code and message. Tokens and private keys are never logged or exposed.
Node.js 18+ is required (ES2022 target).
node --version # v18.x or higherYou need a GitHub App installed on your target organization or account. The app grants the server permission to create issues without sharing personal access tokens with the agent.
Create the app:
https://github.com/settings/installations/<INSTALLATION_ID>)| Variable | Required | Description |
|---|---|---|
GITHUB_APP_ID | Yes | App ID from your GitHub App settings page |
GITHUB_INSTALLATION_ID | Yes | Installation ID from the app installation URL |
GITHUB_PRIVATE_KEY | Yes | Path to the .pem file or the key as a base64-encoded string |
ALLOWED_REPOS | Yes | Comma-separated list of owner/repo entries the agent may target |
RATE_LIMIT_PER_MINUTE | No | Max issue creations per minute (default: 10) |
See .env.example for a documented template.
git clone <repo-url> git-issuer-mcp
cd git-issuer-mcp
npm install
npm run buildThe compiled output lands in dist/.
Tests use Jest with ts-jest and do not require GitHub credentials — all external calls are mocked.
npm testThis runs the full suite covering:
To type-check without running tests:
npm run typecheckAdd the server to your Claude Code MCP configuration at ~/.claude.json:
{
"mcpServers": {
"git-issuer": {
"command": "node",
"args": ["/absolute/path/to/git-issuer-mcp/dist/server.js"],
"env": {
"GITHUB_APP_ID": "123456",
"GITHUB_INSTALLATION_ID": "78901234",
"GITHUB_PRIVATE_KEY": "/absolute/path/to/private-key.pem",
"ALLOWED_REPOS": "your-org/repo-a,your-org/repo-b",
"RATE_LIMIT_PER_MINUTE": "10"
}
}
}
}Claude Code injects the environment variables into the server process at launch. The agent never sees or controls these values.
After saving the config, restart Claude Code. The create_issue tool will appear in the agent's available tools.
Add the server to your Cursor MCP configuration. Open Settings > MCP (or edit .cursor/mcp.json in your project root) and add:
{
"mcpServers": {
"git-issuer": {
"command": "node",
"args": ["/absolute/path/to/git-issuer-mcp/dist/server.js"],
"env": {
"GITHUB_APP_ID": "123456",
"GITHUB_INSTALLATION_ID": "78901234",
"GITHUB_PRIVATE_KEY": "/absolute/path/to/private-key.pem",
"ALLOWED_REPOS": "your-org/repo-a,your-org/repo-b",
"RATE_LIMIT_PER_MINUTE": "10"
}
}
}
}Restart Cursor after saving. The server will start automatically when the agent invokes the create_issue tool.
create_issueCreate a GitHub issue on an allowed repository.
Input:
| Field | Type | Required | Constraints |
|---|---|---|---|
repo | string | Yes | owner/repo format |
title | string | Yes | 1–200 characters |
body | string | Yes | Max 10,000 characters |
labels | string[] | No | Max 10 labels, each 1–50 characters |
Success response:
{
"success": true,
"issue_number": 42,
"issue_url": "https://github.com/your-org/repo/issues/42"
}Error response:
{
"success": false,
"error": {
"code": "REPO_NOT_ALLOWED",
"message": "Repository your-org/other-repo is not on the allowlist"
}
}Error codes:
| Code | Meaning |
|---|---|
VALIDATION_ERROR | Input failed schema validation or sanitization |
REPO_NOT_ALLOWED | Repository is not in ALLOWED_REPOS |
RATE_LIMITED | Too many requests within the rate-limit window |
GITHUB_API_ERROR | GitHub API returned an error |
UNAUTHORIZED | GitHub App authentication failed |
ALLOWED_REPOS. Everything else is rejected.<script> blocks, HTML event attributes, and base64 payloads are stripped or rejected before reaching GitHub.src/
├── server.ts # Entry point — registers tools, starts stdio transport
├── mcp/
│ └── tools.ts # Tool schema and handler (validation → rate limit → create)
├── github/
│ ├── auth.ts # GitHub App JWT + installation token with caching
│ └── issues.ts # Issue creation, allowlist enforcement, structured logging
├── security/
│ ├── validation.ts # Zod schema, HTML sanitization, base64 detection
│ └── rateLimiter.ts # Sliding-window per-agent rate limiter
└── __tests__/
├── auth.test.ts
├── issues.test.ts
├── rateLimiter.test.ts
├── tools.test.ts
└── validation.test.tsnpm install # Install dependencies
npm run build # Compile TypeScript to dist/
npm run typecheck # Type-check without emitting
npm test # Run test suite
npm start # Start the server (requires env vars)Internal use only.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.