[ ⌘K ]
← BACK TO SEARCH

as950118/apidocs-mcp-server

critical

No description

MCP server (purpose undetermined)

purpose: MCP server (purpose undetermined)threat: network exposed
Python0May 20, 2026May 20, 2026GITHUB
5/20/2026
high1 finding
server.py
77    def fetch_swagger_docs(self, base_url: str, cookies: Optional[Dict[str, str]] = None) -> Optional[Dict]:
78        common_paths = ['/swagger.json', '/api-docs', '/openapi.json', '/v2/api-docs', '/v3/api-docs']
79        for path in common_paths:
80            try:
81                url = urljoin(base_url, path)
82                response = self.session.get(url, timeout=10, cookies=cookies, verify=False)
83                if response.status_code == 200:
84                    logger.info(f"성공적으로 Swagger 문서를 {url} 에서 찾았습니다.")
85                    return response.json()
86            except requests.RequestException as e:
87                logger.debug(f"Swagger 문서 가져오기 실패 {url}: {e}")
88        return None
server.py:289-293server.py:77-89

// Exploitable if MCP is exposed to untrusted prompts (network_exposed). For local-only, requires compromised LLM.

The tools accept a user-supplied URL and make HTTP requests to that URL without any validation or restriction. An attacker can provide URLs pointing to internal services (e.g., http://localhost:8080, http://169.254.169.254/latest/meta-data/) to perform SSRF attacks, potentially accessing internal resources or cloud metadata.

ImpactAn attacker could use the MCP server as a proxy to scan internal networks, access cloud metadata (e.g., AWS IAM credentials), or interact with internal services that are not intended to be exposed.

FixImplement a URL allowlist or blocklist, validate that the URL scheme is HTTPS only, and restrict requests to external domains only. Alternatively, use a dedicated HTTP client with network policies to prevent access to private IP ranges.

high1 finding
server.py
91    def fetch_html_docs(self, url: str, cookies: Optional[Dict[str, str]] = None) -> Optional[str]:
92        try:
93            response = self.session.get(url, timeout=10, cookies=cookies, verify=False)
94            if response.status_code == 200:
95                logger.info(f"성공적으로 HTML 문서를 {url} 에서 가져왔습니다.")
96                return response.text
97        except requests.RequestException as e:
98            logger.error(f"HTML 문서 가져오기 실패: {e}")
99        return None
server.py:289-293server.py:302-310server.py:91-100

// Exploitable if MCP is exposed to untrusted prompts (network_exposed). For local-only, requires compromised LLM.

The fetch_html_docs method also makes HTTP GET requests to user-supplied URLs without validation. Additionally, in analyze_api_docs, the HTML content is parsed and a JSON URL is extracted from it, which is then fetched. This allows an attacker to control the final URL via the HTML content, potentially leading to SSRF.

ImpactSame as above, but also allows chained SSRF where the attacker hosts a malicious HTML page that redirects the fetch to internal resources.

FixSame as above. Additionally, validate any extracted URLs from HTML content before fetching.

medium1 finding
server.py
289@tool(server)
290def analyze_api_docs(
291    url: str = Field(..., description="분석할 API 문서의 URL (Swagger/OpenAPI JSON 또는 HTML 페이지)"),
292    cookies: Optional[Dict[str, str]] = Field(None, description="인증에 필요한 쿠키 (예: {'_oauth2_proxy': 'value'})")
293) -> str:
server.py:289-293

// Exploitable if MCP is exposed to untrusted prompts (network_exposed). For local-only, requires compromised LLM.

All tools accept a 'url' parameter without any validation on the scheme (http vs https) or host. This allows an attacker to specify file:// URLs or other schemes that might be handled by the requests library or cause unexpected behavior.

ImpactPotential for protocol smuggling or accessing local files if the requests library supports file:// (though it typically does not). More importantly, it enables SSRF as described above.

FixValidate that the URL uses HTTPS and is not a private IP address. Use a URL parser to check the host and scheme.

medium1 finding
server.py
292    cookies: Optional[Dict[str, str]] = Field(None, description="인증에 필요한 쿠키 (예: {'_oauth2_proxy': 'value'})")
server.py:289-293

// Exploitable if MCP is exposed to untrusted prompts (network_exposed). For local-only, requires compromised LLM.

The tools accept cookies as a parameter, which may contain sensitive authentication tokens. These cookies are passed in plaintext through the MCP protocol and may be logged or exposed in error messages. Additionally, they are stored in the analyzer's session and reused across requests.

ImpactAn attacker with access to logs or MCP communication could steal authentication cookies, gaining unauthorized access to the target API.

FixAvoid passing cookies directly; use a secure credential store or token-based authentication. If necessary, ensure cookies are not logged and are transmitted over encrypted channels.

low1 finding
server.py
184    def health_check_endpoint(self, base_url: str, endpoint: APIEndpoint, timeout: int = 5) -> APIHealthCheck:
185        try:
186            url = urljoin(base_url, endpoint.path)
187            start_time = datetime.now()
188            if endpoint.method == 'GET':
189                response = self.session.get(url, timeout=timeout, verify=False)
190            elif endpoint.method == 'POST':
191                response = self.session.post(url, json={}, timeout=timeout, verify=False)
192            else:
193                response = self.session.get(url, timeout=timeout, verify=False)
194            ...
server.py:386-424server.py:184-225

// Exploitable if MCP is exposed to untrusted prompts (network_exposed). For local-only, requires compromised LLM.

The health_check_api tool sends actual HTTP requests (including POST with empty JSON body) to endpoints discovered from the API docs. This could trigger side effects on the target server, such as creating resources or modifying state, even though the tool claims to only test GET endpoints.

ImpactAn attacker could cause unintended state changes on the target API by triggering POST requests via the health check tool.

FixRestrict health checks to only safe methods (GET/HEAD) and avoid sending any request body. Alternatively, use a dry-run mode.

shell.execnetwork.httpaws.integration
85
LLM-based
low findings+5
high findings+50
medium findings+30