Use with caution. Address findings before production.
Scanned 5/12/2026, 7:15:40 PMยทCached resultยทDeep Scanยท91 rulesยทHow we decide โ
AIVSS Score
Medium
Severity Breakdown
0
critical
2
high
69
medium
6
low
MCP Server Information
Findings
This package carries a C grade with a safety score of 55/100, driven primarily by 49 server configuration issues and 18 resource exhaustion vulnerabilities that could allow denial-of-service attacks or improper system access. While no critical or high-severity vulnerabilities were detected, the 69 medium-severity findingsโincluding prompt injection and data exfiltration risksโsuggest the package lacks security hardening and could expose your system if deployed without additional safeguards. Installation should only proceed if you can implement compensating controls and thoroughly audit the server configuration before production use.
AIPer-finding remediation generated by bedrock-claude-haiku-4-5 โ 40 of 77 findings. Click any finding to read.
No known CVEs found for this package or its dependencies.
Scan Details
Done
Sign in to save scan history and re-scan automatically on new commits.
Building your own MCP server?
Same rules, same LLM judges, same grade. Private scans stay isolated to your account and never appear in the public registry. Required for code your team hasnโt shipped yet.
Showing 1โ30 of 77 findings
77 findings
context7-plugin fetches version-specific documentation and code examples from source repositories and returns them verbatim into LLM context without visible provenance delimiters, enabling indirect prompt injection via untrusted repository content.
Evidence
| 3 | "owner": { |
| 4 | "name": "Upstash" |
| 5 | }, |
| 6 | "plugins": [ |
| 7 | { |
| 8 | "name": "context7-plugin", |
| 9 | "source": "./plugins/claude/context7", |
| 10 | "description": "Up-to-date documentation lookup. Pull version-specific documentation and code examples directly from source repositories into your LLM context.", |
| 11 | "version": "1.0.0" |
| 12 | } |
| 13 | ] |
| 14 | } |
RemediationAI
The context7-plugin returns untrusted repository content directly into LLM context without delimiters, enabling prompt injection attacks. Wrap all fetched documentation and code examples with visible provenance markers (e.g., `[SOURCE: repo/path/file.md]` and `[END SOURCE]`) before returning them in tool responses. This ensures the LLM and user can distinguish injected content from trusted system instructions. Verify by fetching malicious repository content and confirming the markers appear in the tool output.
A variable named like a secret (secret/token/apikey/password/ credential/private_key/bearer) is emitted to a logger, stdout, HTTP response, MCP tool response, or file write without redaction. If the value is genuinely not sensitive, rename it; otherwise wrap with a redaction helper.
Evidence
| 46 | expires_at: |
| 47 | tokens.expires_at ?? (tokens.expires_in ? Date.now() + tokens.expires_in * 1000 : undefined), |
| 48 | }; |
| 49 | fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify(data, null, 2), { mode: 0o600 }); |
| 50 | } |
| 51 | |
| 52 | export function loadTokens(): TokenData | null { |
RemediationAI
The `loadTokens()` and token-handling code writes sensitive token data (expires_at, access tokens) to CREDENTIALS_FILE via `JSON.stringify()` without redaction, risking exposure in logs or error messages. Replace the direct write with a redaction helper: create a `sanitizeTokenData()` function that removes or masks `expires_at`, `access_token`, and `refresh_token` fields before logging, or use a library like `winston-redact` to automatically redact secret-like keys. This prevents accidental token leakage in logs, stdout, or file writes. Verify by checking that `cat CREDENTIALS_FILE` or any logged output does not contain plaintext token values.
User-controlled value printed to terminal without ANSI escape sanitization. Malicious input can inject cursor-control sequences, rewrite earlier output, or hide shell commands from the operator.
Evidence
| 470 | await transport.handleRequest(req, res, req.body); |
| 471 | }); |
| 472 | } catch (error) { |
| 473 | console.error("Error handling MCP request:", error); |
| 474 | if (!res.headersSent) { |
| 475 | res.status(500).json({ |
| 476 | jsonrpc: "2.0", |
RemediationAI
User-controlled error objects are printed to console.error() without ANSI escape sanitization, allowing malicious input to inject cursor-control sequences that rewrite terminal output or hide commands. Sanitize the error message by stripping ANSI escape codes before logging: use a library like `strip-ansi` or a regex `/\x1b\[[0-9;]*m/g` to remove control sequences from `error.toString()` before calling `console.error()`. This prevents terminal injection attacks. Verify by passing an error with embedded ANSI codes (e.g., `\x1b[2J` to clear screen) and confirming the terminal is not affected.
LLM consensus
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 110 | if (accessToken) { |
| 111 | headers["Authorization"] = `Bearer ${accessToken}`; |
| 112 | } |
| 113 | const response = await fetch(`${baseUrl}/api/v2/libs/search?${params}`, { headers }); |
| 114 | return (await response.json()) as LibrarySearchResponse; |
| 115 | } |
RemediationAI
The fetch call to `/api/v2/libs/search` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option to the fetch call: `const response = await fetch(url, { headers, signal: AbortSignal.timeout(5000) })` (or use a polyfill for older Node versions). This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 32 | export async function getSkill(project: string, skillName: string): Promise<SingleSkillResponse> { |
| 33 | const params = new URLSearchParams({ project, skill: skillName }); |
| 34 | const response = await fetch(`${baseUrl}/api/v2/skills?${params}`); |
| 35 | return (await response.json()) as SingleSkillResponse; |
| 36 | } |
RemediationAI
The fetch call to `/api/v2/skills` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 77 | } |
| 78 | |
| 79 | async function refreshAccessToken(refreshToken: string): Promise<TokenData> { |
| 80 | const response = await fetch(`${getBaseUrl()}/api/oauth/token`, { |
| 81 | method: "POST", |
| 82 | headers: { "Content-Type": "application/x-www-form-urlencoded" }, |
| 83 | body: new URLSearchParams({ |
RemediationAI
The fetch call in `refreshAccessToken()` to `/api/oauth/token` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { method: 'POST', headers, body, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 143 | def fetch_with_retry(url, headers, max_retries=3): |
| 144 | for attempt in range(max_retries): |
| 145 | response = requests.get(url, headers=headers) |
| 146 | |
| 147 | if response.status_code == 429: |
| 148 | retry_after = int(response.headers.get("Retry-After", 2 ** attempt)) |
RemediationAI
The Python example in `docs/api-guide.mdx` calls `requests.get(url, headers=headers)` without a timeout parameter, allowing hung servers to block indefinitely. Update the code example to: `response = requests.get(url, headers=headers, timeout=5)` to enforce a 5-second timeout. This prevents thread exhaustion in production code that follows the documentation. Verify by running the example against a slow server and confirming it times out after 5 seconds.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 177 | } |
| 178 | |
| 179 | async function fetchWhoami(accessToken: string): Promise<WhoamiResponse> { |
| 180 | const response = await fetch(`${getBaseUrl()}/api/dashboard/whoami`, { |
| 181 | headers: { |
| 182 | Authorization: `Bearer ${accessToken}`, |
| 183 | }, |
RemediationAI
The fetch call in `fetchWhoami()` to `/api/dashboard/whoami` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { headers, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 200 | const skills: (Skill & { project: string })[] = []; |
| 201 | for (const item of skillMdFiles) { |
| 202 | const rawUrl = `${GITHUB_RAW}/${owner}/${repo}/${branchResult.branch}/${item.path}`; |
| 203 | const response = await fetch(rawUrl, { headers }); |
| 204 | if (!response.ok) continue; |
| 205 | |
| 206 | const content = await response.text(); |
RemediationAI
The fetch call in the GitHub raw content loop lacks an explicit timeout, allowing a hung GitHub server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(rawUrl, { headers, signal: AbortSignal.timeout(5000) })`. This ensures each request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 38 | export async function searchSkills(query: string): Promise<SearchResponse> { |
| 39 | const params = new URLSearchParams({ query }); |
| 40 | const response = await fetch(`${baseUrl}/api/v2/skills?${params}`); |
| 41 | return (await response.json()) as SearchResponse; |
| 42 | } |
RemediationAI
The fetch call in `searchSkills()` to `/api/v2/skills` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 159 | headers: Record<string, string> |
| 160 | ): Promise<GitHubTreeResponse | null> { |
| 161 | const treeUrl = `${GITHUB_API}/repos/${owner}/${repo}/git/trees/${branch}?recursive=1`; |
| 162 | const response = await fetch(treeUrl, { headers }); |
| 163 | if (!response.ok) return null; |
| 164 | return (await response.json()) as GitHubTreeResponse; |
| 165 | } |
RemediationAI
The fetch call in `getGitHubTree()` to the GitHub API lacks an explicit timeout, allowing a hung GitHub server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(treeUrl, { headers, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 97 | const spinner = ora("Configuring authentication...").start(); |
| 98 | |
| 99 | try { |
| 100 | const response = await fetch(`${getBaseUrl()}/api/dashboard/api-keys`, { |
| 101 | method: "POST", |
| 102 | headers: { |
| 103 | Authorization: `Bearer ${accessToken}`, |
RemediationAI
The fetch call in `packages/cli/src/commands/setup.ts` to `/api/dashboard/api-keys` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { method: 'POST', headers, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 515 | const authServerUrl = AUTH_SERVER_URL; |
| 516 | |
| 517 | try { |
| 518 | const response = await fetch(`${authServerUrl}/.well-known/oauth-authorization-server`); |
| 519 | if (!response.ok) { |
| 520 | console.error("[OAuth] Upstream error:", response.status); |
| 521 | return res.status(response.status).json({ |
RemediationAI
The fetch call to `/.well-known/oauth-authorization-server` lacks an explicit timeout, allowing a hung auth server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(authServerUrl + '/.well-known/oauth-authorization-server', { signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
LLM consensus
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 26 | export async function listProjectSkills(project: string): Promise<ListSkillsResponse> { |
| 27 | const params = new URLSearchParams({ project }); |
| 28 | const response = await fetch(`${baseUrl}/api/v2/skills?${params}`); |
| 29 | return (await response.json()) as ListSkillsResponse; |
| 30 | } |
RemediationAI
The fetch call in `listProjectSkills()` to `/api/v2/skills` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 263 | const files: SkillFile[] = []; |
| 264 | for (const item of skillFiles) { |
| 265 | const rawUrl = `${GITHUB_RAW}/${owner}/${repo}/${branch}/${item.path}`; |
| 266 | const fileResponse = await fetch(rawUrl, { headers: ghHeaders }); |
| 267 | |
| 268 | if (!fileResponse.ok) { |
| 269 | console.warn(`Failed to fetch ${item.path}: ${fileResponse.status}`); |
RemediationAI
The fetch call in the GitHub file download loop lacks an explicit timeout, allowing a hung GitHub server to block indefinitely and exhaust connection pools. Add a timeout option: `const fileResponse = await fetch(rawUrl, { headers: ghHeaders, signal: AbortSignal.timeout(5000) })`. This ensures each request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 152 | for (let i = 0; i <= this.retry.attempts; i++) { |
| 153 | try { |
| 154 | res = await fetch(url, requestOptions as RequestInit); |
| 155 | break; |
| 156 | } catch (error_) { |
| 157 | if (requestOptions.signal?.aborted) { |
RemediationAI
The fetch call in the SDK retry loop lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `res = await fetch(url, { ...requestOptions, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 2 | export function trackEvent(event: string, data?: Record<string, unknown>): void { |
| 3 | if (process.env.CTX7_TELEMETRY_DISABLED) return; |
| 4 | fetch(`${getBaseUrl()}/api/v2/cli/events`, { |
| 5 | method: "POST", |
| 6 | headers: { "Content-Type": "application/json" }, |
| 7 | body: JSON.stringify({ event, data }), |
RemediationAI
The fire-and-forget fetch call in `trackEvent()` to `/api/v2/cli/events` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `fetch(url, { method: 'POST', headers, body, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 113 | const headers = generateHeaders(context); |
| 114 | |
| 115 | const response = await fetch(url, { headers }); |
| 116 | if (!response.ok) { |
| 117 | const errorMessage = await parseErrorResponse(response, context.apiKey); |
| 118 | console.error(errorMessage); |
RemediationAI
The fetch call in `packages/mcp/src/lib/api.ts` lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { headers, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 145 | const headers = generateHeaders(context); |
| 146 | |
| 147 | const response = await fetch(url, { headers }); |
| 148 | if (!response.ok) { |
| 149 | const errorMessage = await parseErrorResponse(response, context.apiKey); |
| 150 | console.error(errorMessage); |
RemediationAI
The fetch call in `packages/mcp/src/lib/api.ts` (second instance) lacks an explicit timeout, allowing a hung upstream server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { headers, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 169 | repo: string, |
| 170 | headers: Record<string, string> |
| 171 | ): Promise<{ branch: string } | { status: number }> { |
| 172 | const response = await fetch(`${GITHUB_API}/repos/${owner}/${repo}`, { headers }); |
| 173 | if (!response.ok) return { status: response.status }; |
| 174 | const data = (await response.json()) as { default_branch: string }; |
| 175 | return { branch: data.default_branch }; |
RemediationAI
The fetch call in `getGitHubRepo()` to the GitHub API lacks an explicit timeout, allowing a hung GitHub server to block indefinitely and exhaust connection pools. Add a timeout option: `const response = await fetch(url, { headers, signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
Network / IO / subprocess call without an explicit timeout. A malicious or hung upstream (HTTP host, socket peer, child process) can pin threads, exhaust connection/process pools, and make the MCP server unresponsive. Always pass a bounded timeout. v2 extends v1 with subprocess coverage (R03 from the legacy readiness audit).
Evidence
| 41 | async function fetchRule(filename: string, fallback: string): Promise<string> { |
| 42 | for (const base of GITHUB_RAW_URLS) { |
| 43 | try { |
| 44 | const res = await fetch(`${base}/${filename}`); |
| 45 | if (res.ok) return await res.text(); |
| 46 | } catch { |
| 47 | continue; |
RemediationAI
The fetch call in `fetchRule()` to GitHub raw URLs lacks an explicit timeout, allowing a hung GitHub server to block indefinitely and exhaust connection pools. Add a timeout option: `const res = await fetch(url, { signal: AbortSignal.timeout(5000) })`. This ensures the request fails after 5 seconds instead of hanging. Verify by testing with a timeout-inducing server and confirming the request aborts within the specified window.
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 1637 | "type": "string", |
| 1638 | "description": "Title of the code snippet" |
| 1639 | }, |
| 1640 | "codeDescription": { |
| 1641 | "type": "string", |
| 1642 | "description": "Description of what the code does" |
| 1643 | }, |
| 1644 | "codeLanguage": { |
| 1645 | "type": "string", |
| 1646 | "description": "Primary programming language" |
RemediationAI
The `codeDescription` field in the OpenAPI schema is an unconstrained string with a risky name, allowing arbitrary input that could be used for injection attacks. Constrain the schema by adding `maxLength: 500` and optionally a `pattern` to the field definition in `docs/openapi.json`: `"codeDescription": { "type": "string", "maxLength": 500, "description": "Description of what the code does" }`. This limits the blast radius of the tool. Verify by attempting to pass a very long or malicious string and confirming it is rejected or truncated.
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 1691 | "type": "string", |
| 1692 | "description": "Programming language" |
| 1693 | }, |
| 1694 | "code": { |
| 1695 | "type": "string", |
| 1696 | "description": "The actual code content" |
| 1697 | } |
| 1698 | }, |
| 1699 | "required": [ |
| 1700 | "language", |
RemediationAI
The `code` field in the OpenAPI schema is an unconstrained string with a risky name, allowing arbitrary code input that could be used for injection attacks. Constrain the schema by adding `maxLength: 10000` to the field definition in `docs/openapi.json`: `"code": { "type": "string", "maxLength": 10000, "description": "The actual code content" }`. This limits the blast radius of the tool. Verify by attempting to pass a very long or malicious string and confirming it is rejected or truncated.
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 1633 | "type": "object", |
| 1634 | "description": "A code snippet from library documentation", |
| 1635 | "properties": { |
| 1636 | "codeTitle": { |
| 1637 | "type": "string", |
| 1638 | "description": "Title of the code snippet" |
| 1639 | }, |
| 1640 | "codeDescription": { |
| 1641 | "type": "string", |
| 1642 | "description": "Description of what the code does" |
RemediationAI
The `codeTitle` and `codeDescription` fields in the code snippet schema are unconstrained strings with risky names, allowing arbitrary input for injection attacks. Constrain the schema by adding `maxLength: 200` to both fields in `docs/openapi.json`: `"codeTitle": { "type": "string", "maxLength": 200 }` and `"codeDescription": { "type": "string", "maxLength": 200 }`. This limits the blast radius of the tool. Verify by attempting to pass very long or malicious strings and confirming they are rejected or truncated.
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 1649 | "type": "integer", |
| 1650 | "description": "Token count for the snippet" |
| 1651 | }, |
| 1652 | "codeId": { |
| 1653 | "type": "string", |
| 1654 | "description": "URL to source location" |
| 1655 | }, |
| 1656 | "pageTitle": { |
| 1657 | "type": "string", |
| 1658 | "description": "Title of the documentation page" |
RemediationAI
The `codeId` field is an unconstrained string with a risky name (URL-like), allowing arbitrary input for injection attacks. Constrain the schema by adding `maxLength: 500` and a URL pattern to the field definition in `docs/openapi.json`: `"codeId": { "type": "string", "maxLength": 500, "pattern": "^https?://" }`. This limits the blast radius of the tool. Verify by attempting to pass a very long or non-URL string and confirming it is rejected.
MCP tool input schema exposes an unconstrained string/any field with a risky name (command/query/sql/code/script/url/path/expr/ eval). Any caller can pass arbitrary values, which typically widens the tool's blast radius well beyond its intent. Narrow the schema with `.enum()`, `.regex()`, `.max()`, `Literal[...]`, Pydantic `Field(max_length=..., pattern=...)`, or a JSON Schema `enum` / `pattern` / `maxLength`.
Evidence
| 1641 | "type": "string", |
| 1642 | "description": "Description of what the code does" |
| 1643 | }, |
| 1644 | "codeLanguage": { |
| 1645 | "type": "string", |
| 1646 | "description": "Primary programming language" |
| 1647 | }, |
| 1648 | "codeTokens": { |
| 1649 | "type": "integer", |
| 1650 | "description": "Token count for the snippet" |
RemediationAI
The `codeLanguage` field is an unconstrained string with a risky name, allowing arbitrary input for injection attacks. Constrain the schema by adding an `enum` list of allowed languages to the field definition in `docs/openapi.json`: `"codeLanguage": { "type": "string", "enum": ["javascript", "python", "java", "go", "rust"] }`. This limits the blast radius of the tool. Verify by attempting to pass an unlisted language and confirming it is rejected.
Dockerfile never sets a non-root `USER` directive, so the CMD runs as root by default. Any RCE or library-level vulnerability exploited inside this container gets full privileges (MCP Top-10 R3). Add `USER <non-root>` before CMD / ENTRYPOINT in the final stage โ e.g. `USER 1000`, `USER nobody`, or `USER nonroot` on distroless.
Evidence
| 1 | # ----- Build Stage ----- |
| 2 | FROM node:lts-alpine AS builder |
| 3 | RUN corepack enable pnpm |
| 4 | WORKDIR /app |
| 5 | |
| 6 | # Copy monorepo config and install dependencies |
| 7 | COPY package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.json ./ |
| 8 | COPY packages/mcp ./packages/mcp |
| 9 | RUN pnpm install --frozen-lockfile |
| 10 | |
| 11 | # Build the mcp package |
| 12 | RUN pnpm --filter @upstash/context7-mcp build |
| 13 | |
| 14 | # ----- Production Stage ----- |
| 15 | FROM node:lts-alpine |
| 16 | RUN corepack enable pnpm |
| 17 | WORKDIR /app |
| 18 | |
| 19 | # Install production dependencies only |
| 20 | COPY package.js |
RemediationAI
The Dockerfile runs the MCP server as root by default, allowing any RCE or library vulnerability to gain full system privileges. Add a non-root `USER` directive before the `CMD` in the final stage of `packages/mcp/Dockerfile`: `USER 1000` or `USER nobody` (or use a distroless image with `USER nonroot`). This limits the blast radius of container escapes. Verify by running the container and confirming `whoami` returns a non-root user.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - ุชูุซูู ุฃููุงุฏ ู
ุญุฏุซ ูุฃู ุฃู
ุฑ ุจุฑู
ุฌู |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="Install in VS Code (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A%22cont |
RemediationAI
The MCP manifest in `packages/mcp/mcpb/manifest.json` declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 |  |
| 2 | |
| 3 | [](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D) |
| 4 | |
| 5 | # Context7 MCP - ๅณๆๆดๆฐ็็จๅผ็ขผๆไปถ๏ผ้ฉ็จๆผไปปไฝๆ็คบ |
| 6 | |
| 7 | [](https://context7.com) [](https://smithery.ai/server/@upstash/cont |
RemediationAI
The MCP manifest (referenced in i18n/README.ar.md) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - Documentazione aggiornata per qualsiasi prompt |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="Install in VS Code (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Installa%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22 |
RemediationAI
The MCP manifest (referenced in i18n/README.zh-TW.md) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - Documentaรงรฃo de Cรณdigo Atualizada para Qualquer Prompt |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) |
| 4 | [<img alt="Instalar no Cursor" src="https://img.shields.io/badge/Instalar%20no%20CURSOR-000000?style=for-the-badge&logo=cursor&logoColor=white">](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRw |
RemediationAI
The MCP manifest (referenced in i18n/README.it.md) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | --- |
| 2 | title: Developer Guide |
| 3 | description: Set up and run Context7 MCP locally for development |
| 4 | --- |
| 5 | |
| 6 | This guide covers how to set up the Context7 MCP server locally for development and testing. |
| 7 | |
| 8 | ## Getting Started |
| 9 | |
| 10 | Clone the project and install dependencies: |
| 11 | |
| 12 | ```bash |
| 13 | git clone https://github.com/upstash/context7.git |
| 14 | cd context7 |
| 15 | pnpm i |
| 16 | ``` |
| 17 | |
| 18 | Build: |
| 19 | |
| 20 | ```bash |
| 21 | pnpm run build |
| 22 | ``` |
| 23 | |
| 24 | Run the server: |
| 25 | |
| 26 | ```bash |
| 27 | node packages/mcp/dist/index.js |
| 28 | ``` |
| 29 | |
| 30 | ## CLI Arguments |
| 31 | |
| 32 | `context7-mcp` accepts the following CLI flags |
RemediationAI
The MCP manifest (referenced in i18n/README.pt-BR.md) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | --- |
| 2 | title: Troubleshooting |
| 3 | --- |
| 4 | |
| 5 | This guide helps you resolve common issues when setting up or using Context7 MCP. |
| 6 | |
| 7 | ## Quick Checklist |
| 8 | |
| 9 | - Confirm Node.js v18+ is installed (`node --version`) |
| 10 | - Update to the latest Context7 MCP package (`@upstash/context7-mcp@latest`) |
| 11 | - Verify connectivity with `curl https://mcp.context7.com/ping` |
| 12 | - Add your API key to the configuration if you hit rate limits |
| 13 | - Enable debug logs (`DEBUG=*`) before collecting support information |
| 14 | |
| 15 | <Tip> |
| 16 | **Skip Node.js issues entir |
RemediationAI
The MCP manifest (referenced in docs/resources/developer.mdx) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - Herhangi Bir Prompt ฤฐรงin Gรผncel Kod Belgeleri |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="VS Code'da Yรผkle (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Context7%20MCP%20Y%C3%BCkle&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22n |
RemediationAI
The MCP manifest (referenced in docs/resources/troubleshooting.mdx) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 |  |
| 2 | |
| 3 | [](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D) |
| 4 | |
| 5 | # Context7 MCP - ๋ชจ๋ ํ๋กฌํํธ๋ฅผ ์ํ ์ต์ ์ฝ๋ ๋ฌธ์ |
| 6 | |
| 7 | [](https://context7.com) [](https://smithery.ai/server/@upstash/con |
RemediationAI
The MCP manifest (referenced in i18n/README.tr.md) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - Tร i Liแปu Code Cแบญp Nhแบญt Cho Mแปi Prompt |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="Install in VS Code (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name%22%3A |
RemediationAI
The MCP manifest (referenced in i18n/README.ko.md) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - Documentaciรณn Actualizada Para Cualquier Prompt |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="Instalar en VS Code (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Instalar%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3 |
RemediationAI
The MCP manifest (referenced in i18n/README.vi.md) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | name: Bug Report |
| 2 | description: Report a bug or issue with Context7 MCP |
| 3 | title: "[Bug]: " |
| 4 | labels: ["bug", "needs-triage"] |
| 5 | body: |
| 6 | - type: markdown |
| 7 | attributes: |
| 8 | value: | |
| 9 | Thanks for taking the time to report this issue! Please fill out the form below to help us investigate. |
| 10 | |
| 11 | - type: dropdown |
| 12 | id: client |
| 13 | attributes: |
| 14 | label: MCP Client |
| 15 | description: Which MCP client are you using? |
| 16 | options: |
| 17 | - Cursor |
| 18 | - Claude Desktop |
| 19 | - Claude Code |
| 20 | |
RemediationAI
The MCP manifest (referenced in i18n/README.es.md) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | { |
| 2 | "manifest_version": "0.3", |
| 3 | "name": "context7", |
| 4 | "display_name": "Context7", |
| 5 | "version": "2.1.0", |
| 6 | "description": "Up-to-date Code Docs For Any Prompt", |
| 7 | "long_description": "Context7 MCP pulls up-to-date, version-specific documentation and code examples straight from the source โ and places them directly into your prompt.", |
| 8 | "author": { |
| 9 | "name": "Upstash", |
| 10 | "email": "context7@upstash.com", |
| 11 | "url": "https://upstash.com" |
| 12 | }, |
| 13 | "homepage": "https://context7.com", |
| 14 | "documentati |
RemediationAI
The MCP manifest (referenced in .github/ISSUE_TEMPLATE/bug_report.yml) declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 |  |
| 2 | |
| 3 | [](https://cursor.com/en/install-mcp?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0%3D) |
| 4 | |
| 5 | # Context7 MCP - ๆๆฐๆๆกฃ่ต่ฝๆฏไธชๆ็คบ่ฏ |
| 6 | |
| 7 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mc |
RemediationAI
The MCP manifest in `packages/mcp/mcpb/manifest.json` declares tools but does not include an `auth` or `authorization` field, making it unclear how the server authenticates requests. Add an explicit authentication field to the manifest: `"auth": { "type": "oauth2" }` or `"auth": { "type": "bearer" }` depending on the actual mechanism used. This allows reviewers to audit the security model. Verify by checking that the manifest now includes the auth field and matches the actual implementation.
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP โ ะะบััะฐะปัะฝะฐ ะดะพะบัะผะตะฝัะฐััั ะท ะฟัะธะบะปะฐะดะฐะผะธ ะบะพะดั ะดะปั ะฑัะดั-ัะบะพะณะพ ะทะฐะฟะธัั |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="Install in VS Code (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Fi |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - Documentation ร jour pour vos prompts |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="Installer dans VS Code (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Installer%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22nam |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - ะะบััะฐะปัะฝะฐั ะดะพะบัะผะตะฝัะฐัะธั ะดะปั ะปัะฑะพะณะพ ะฟัะพะผะฟัะฐ |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="Install in VS Code (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22name% |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - Dokumentasi Kode Terkini Untuk Setiap Permintaan |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="Install in VS Code (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%2 |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | { |
| 2 | "mcpServers": { |
| 3 | "context7": { |
| 4 | "url": "https://mcp.context7.com/mcp" |
| 5 | } |
| 6 | } |
| 7 | } |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | # Context7 MCP - Aktuelle Dokumentation fรผr jeden Prompt |
| 2 | |
| 3 | [](https://context7.com) [](https://smithery.ai/server/@upstash/context7-mcp) [<img alt="In VS Code installieren (npx)" src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Context7%20MCP&color=0098FF">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%7B%22nam |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | { |
| 2 | "name": "context7", |
| 3 | "description": "Up-to-date code docs for any prompt", |
| 4 | "version": "1.0.0", |
| 5 | "settings": [ |
| 6 | { |
| 7 | "name": "API Key", |
| 8 | "description": "Context7 API key. Create new key at https://context7.com/dashboard.", |
| 9 | "envVar": "CONTEXT7_API_KEY" |
| 10 | } |
| 11 | ], |
| 12 | "mcpServers": { |
| 13 | "context7": { |
| 14 | "command": "npx", |
| 15 | "args": ["-y", "@upstash/context7-mcp", "--api-key", "${CONTEXT7_API_KEY}"] |
| 16 | } |
| 17 | } |
| 18 | } |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | --- |
| 2 | title: Factory AI |
| 3 | sidebarTitle: Factory AI |
| 4 | description: AI-native software development platform with Droids |
| 5 | --- |
| 6 | |
| 7 | [Factory AI](https://factory.ai) is a coding agent platform that uses "Droids" to handle development tasks. By connecting Context7 as an MCP server, Factory Droids can access up-to-date library documentation during coding tasks. |
| 8 | |
| 9 | For more details on how Factory AI handles MCP, see the [Factory AI MCP documentation](https://docs.factory.ai/cli/configuration/mcp). |
| 10 | |
| 11 | ## Setup |
| 12 | |
| 13 | There a |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
MCP manifest declares tools but no authentication field is present (none of: auth, authorization, bearer, oauth, mtls, apiKey, api_key, basic, token, authToken). Absence is a weak signal โ confirm whether the server relies on network-layer or host-level auth, or declare the real mechanism explicitly so reviewers can audit it.
Evidence
| 1 | --- |
| 2 | title: "On-Premise Deployment" |
| 3 | sidebarTitle: "Getting Started" |
| 4 | --- |
| 5 | |
| 6 | Context7 On-Premise lets you run the full Context7 stack inside your own infrastructure. Your code, documentation, and embeddings never leave your environment. |
| 7 | |
| 8 | ## What's Included |
| 9 | |
| 10 | - Full Context7 parsing and indexing pipeline |
| 11 | - Local vector storage (no external vector DB required) |
| 12 | - Built-in MCP server. Works with any MCP-compatible AI client |
| 13 | - Web UI for managing indexed libraries and configuration |
| 14 | - REST API compatible wi |
Remediation
Declare a real authentication mechanism in the manifest, matching what the running server actually enforces: - `"auth": "bearer"` with a token scheme documented for callers - `"auth": "oauth"` / `"oauth2": { ... }` for delegated flows - `"apiKey": { "header": "X-API-Key", "prefix": "..." }` - `"mtls": true` when client certificates are required If the server is intentionally unauthenticated (stdio-only, local developer tool, trusted-host network), document the assumption in the manifest via a `"
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 15 | fetch-depth: 0 |
| 16 | |
| 17 | - name: Check for changeset |
| 18 | uses: actions/github-script@v7 |
| 19 | with: |
| 20 | script: | |
| 21 | const { execSync } = require('child_process'); |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 19 | uses: actions/checkout@v6 |
| 20 | |
| 21 | - name: Setup Node |
| 22 | uses: actions/setup-node@v4 |
| 23 | with: |
| 24 | node-version: "20" |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 35 | - name: Build and push Docker image |
| 36 | id: build-push |
| 37 | uses: docker/build-push-action@v6 |
| 38 | with: |
| 39 | context: . |
| 40 | file: packages/mcp/Dockerfile |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 24 | node-version: "20" |
| 25 | |
| 26 | - name: Setup pnpm |
| 27 | uses: pnpm/action-setup@v4 |
| 28 | with: |
| 29 | version: 10 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 31 | uses: docker/setup-qemu-action@v3 |
| 32 | |
| 33 | - name: Set up Docker Buildx |
| 34 | uses: docker/setup-buildx-action@v3 |
| 35 | |
| 36 | - name: Build and push Docker image |
| 37 | id: build-push |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 20 | uses: actions/checkout@v6 |
| 21 | |
| 22 | - name: Setup Node |
| 23 | uses: actions/setup-node@v4 |
| 24 | with: |
| 25 | node-version: lts/* |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 28 | uses: aws-actions/amazon-ecr-login@v2 |
| 29 | |
| 30 | - name: Set up QEMU |
| 31 | uses: docker/setup-qemu-action@v3 |
| 32 | |
| 33 | - name: Set up Docker Buildx |
| 34 | uses: docker/setup-buildx-action@v3 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 14 | steps: |
| 15 | - name: Checkout code |
| 16 | uses: actions/checkout@v6 |
| 17 | |
| 18 | - name: Configure AWS credentials |
| 19 | uses: aws-actions/configure-aws-credentials@v5 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 22 | node-version: "20" |
| 23 | |
| 24 | - name: Setup pnpm |
| 25 | uses: pnpm/action-setup@v4 |
| 26 | with: |
| 27 | version: 10 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 25 | - name: Login to Amazon ECR |
| 26 | id: login-ecr |
| 27 | uses: aws-actions/amazon-ecr-login@v2 |
| 28 | |
| 29 | - name: Set up QEMU |
| 30 | uses: docker/setup-qemu-action@v3 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 17 | - uses: actions/checkout@v6 |
| 18 | |
| 19 | - name: Setup Node |
| 20 | uses: actions/setup-node@v4 |
| 21 | with: |
| 22 | node-version: "20" |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 26 | node-version: "20" |
| 27 | |
| 28 | - name: Setup pnpm |
| 29 | uses: pnpm/action-setup@v4 |
| 30 | with: |
| 31 | version: 10 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 17 | uses: actions/checkout@v6 |
| 18 | |
| 19 | - name: Configure AWS credentials |
| 20 | uses: aws-actions/configure-aws-credentials@v5 |
| 21 | with: |
| 22 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} |
| 23 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 16 | pull-requests: write |
| 17 | steps: |
| 18 | - name: Checkout Repo |
| 19 | uses: actions/checkout@v6 |
| 20 | |
| 21 | - name: Setup Node |
| 22 | uses: actions/setup-node@v4 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 21 | ref: ${{ inputs.branch || github.ref }} |
| 22 | |
| 23 | - name: Setup Node |
| 24 | uses: actions/setup-node@v4 |
| 25 | with: |
| 26 | node-version: "20" |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 16 | contents: read |
| 17 | steps: |
| 18 | - name: Checkout Repo |
| 19 | uses: actions/checkout@v6 |
| 20 | with: |
| 21 | ref: ${{ inputs.branch || github.ref }} |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 10 | runs-on: ubuntu-latest |
| 11 | steps: |
| 12 | - name: Checkout Repo |
| 13 | uses: actions/checkout@v6 |
| 14 | with: |
| 15 | fetch-depth: 0 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 14 | test: |
| 15 | runs-on: ubuntu-latest |
| 16 | steps: |
| 17 | - uses: actions/checkout@v6 |
| 18 | |
| 19 | - name: Setup Node |
| 20 | uses: actions/setup-node@v4 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 33 | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT |
| 34 | |
| 35 | - name: Cache pnpm dependencies |
| 36 | uses: actions/cache@v5 |
| 37 | with: |
| 38 | path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} |
| 39 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 40 | - name: Create Release PR or Publish |
| 41 | id: changesets |
| 42 | uses: changesets/action@v1 |
| 43 | with: |
| 44 | publish: pnpm release |
| 45 | commit: "chore(release): version packages" |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
GitHub Actions `uses:` reference is not pinned to a 40-character commit SHA. Tags (`@v4`) and branches (`@main`) are mutable โ a compromised maintainer or a tag rewrite can substitute malicious code into your CI pipeline silently. Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. For readability, include the version as a trailing comment: `# v4.1.1`. Tools like `pinact` / `ratchet` automate this. Allowed unpinned forms (excluded by the rule): - Local actions `.
Evidence
| 17 | contents: read |
| 18 | steps: |
| 19 | - name: Checkout Repo |
| 20 | uses: actions/checkout@v6 |
| 21 | |
| 22 | - name: Setup Node |
| 23 | uses: actions/setup-node@v4 |
Remediation
Pin every `uses:` to a 40-character commit SHA. Trailing comment with the version helps reviewers: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v4.1.1` Automate the migration with `pinact` (https://github.com/suzuki-shunsuke/pinact) or `ratchet` (https://github.com/sethvargo/ratchet). Add a `pinact run --check` pre-commit hook so future PRs stay pinned. Re-pin when the action releases a new version โ Dependabot can do this automatically with `version-update-strategy: inc
Time-of-check-to-time-of-use race. Code calls `os.path.exists` / `fs.existsSync` to check a path, then `open` / `readFileSync` / `unlink` on the same name within a few lines โ without a lock or atomic-open. An attacker who can race the filesystem (symlink, file replacement) between the check and the use gets the action applied to a different target. Replace the check-then-use pattern with the action's own error handling: try the open and catch FileNotFoundError / ENOENT. For atomic creation use
Evidence
| 1 | import * as crypto from "crypto"; |
| 2 | import * as http from "http"; |
| 3 | import * as fs from "fs"; |
| 4 | import * as path from "path"; |
| 5 | import * as os from "os"; |
| 6 | import { CLI_CLIENT_ID } from "../constants.js"; |
| 7 | import { getBaseUrl } from "./api.js"; |
| 8 | |
| 9 | const CONFIG_DIR = path.join(os.homedir(), ".context7"); |
| 10 | const CREDENTIALS_FILE = path.join(CONFIG_DIR, "credentials.json"); |
| 11 | |
| 12 | export interface TokenData { |
| 13 | access_token: string; |
| 14 | refresh_token?: string; |
| 15 | token_type: string; |
| 16 | expires_in?: number; |
| 17 | expires_at?: |
Remediation
Replace check-then-use with action-then-handle: Python: `try: with open(p) as f: ... except FileNotFoundError: ...` Node: `try { fs.readFileSync(p); } catch (e) { if (e.code === "ENOENT") ... }` For atomic file creation: Python: `os.open(p, os.O_RDWR | os.O_CREAT | os.O_EXCL)` Node: `fs.open(p, "wx")` โ fails if file exists, no race. When you genuinely must check first, use `flock` (Python `fcntl`) or a similar per-process advisory lock to make the window uninteresting to a
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 93 | try { |
| 94 | await access(candidate); |
| 95 | return candidate; |
| 96 | } catch {} |
| 97 | } |
| 98 | return candidates[0]; |
| 99 | } |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 557 | let content = ""; |
| 558 | try { |
| 559 | content = await readFile(filePath, "utf-8"); |
| 560 | } catch {} |
| 561 | |
| 562 | if (content.includes(marker)) { |
| 563 | const regex = new RegExp(`${escapedMarker}\\n[\\s\\S]*?${escapedMarker}`); |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 97 | try { |
| 98 | await access(join(baseDir, dirname(universalPath))); |
| 99 | hasUniversalDir = true; |
| 100 | } catch {} |
| 101 | |
| 102 | const detectedIdes: IDE[] = [ |
| 103 | ...(hasUniversalDir ? (["universal"] as IDE[]) : []), |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 60 | try { |
| 61 | await access(join(baseDir, parentDir)); |
| 62 | detected.push(ide); |
| 63 | } catch {} |
| 64 | } |
| 65 | |
| 66 | return detected; |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 145 | let existing = ""; |
| 146 | try { |
| 147 | existing = await readFile(filePath, "utf-8"); |
| 148 | } catch {} |
| 149 | |
| 150 | const sectionHeader = `[mcp_servers.${serverName}]`; |
| 151 | const alreadyExists = existing.includes(sectionHeader); |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.
Silent error swallowing detected. An except clause that does pass or ... discards the exception with no log, no metric, and no trace. This blinds incident response and hides real failures.
Evidence
| 42 | if (stats.isSymbolicLink() || stats.isDirectory()) { |
| 43 | await rm(targetPath, { recursive: true }); |
| 44 | } |
| 45 | } catch {} |
| 46 | |
| 47 | await mkdir(skillsRoot, { recursive: true }); |
| 48 | await symlink(sourcePath, targetPath); |
Remediation
Log the exception at minimum (`logger.exception(e)`), emit a metric, or re-raise if the error is not recoverable. If you genuinely want to ignore an exception, say so with a comment.