VYPR
Medium severity6.3NVD Advisory· Published Jun 3, 2026

CVE-2026-10690

CVE-2026-10690

Description

CVE-2026-10690: DesktopCommanderMCP 0.2.37 is vulnerable to SSRF via the readFileFromUrl function, allowing remote attackers to make arbitrary requests.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

CVE-2026-10690: DesktopCommanderMCP 0.2.37 is vulnerable to SSRF via the readFileFromUrl function, allowing remote attackers to make arbitrary requests.

Vulnerability

A Server-Side Request Forgery (SSRF) vulnerability exists in wonderwhy-er DesktopCommanderMCP version 0.2.37. The readFileFromUrl function within the read_file tool does not validate the url argument when isUrl is set to true. This allows the server to be tricked into making arbitrary HTTP requests to internal or external resources [2].

Exploitation

An attacker can exploit this vulnerability by providing a malicious URL as the path parameter to the read_file function, with the isUrl flag set to true. The server will then fetch the content from the attacker-controlled URL without any validation of the destination, potentially interacting with internal network services or cloud metadata endpoints [2].

Impact

Successful exploitation of this vulnerability allows an attacker to perform arbitrary HTTP requests from the server's network context. This can lead to the disclosure of sensitive information from internal services, cloud metadata, or other network-accessible resources, effectively achieving information disclosure and potentially enabling further attacks depending on the server's network environment [2].

Mitigation

The vulnerability is addressed in a commit that introduces a validateFetchUrl function to block SSRF attack vectors, including non-HTTP(S) schemes, private IP ranges, loopback addresses, and common internal hostnames. Users should update to a patched version. The specific patch commit is 53699bebba9950047bca16ac4dc8f0568f596aaa [3].

AI Insight generated on Jun 3, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

1
53699bebba99

fix(security): prevent SSRF in read_file URL fetching

https://github.com/sorlen008/DesktopCommanderMCPSaeed Al MansouriApr 3, 2026via nvd-ref
1 file changed · +82 3
  • src/tools/filesystem.ts+82 3 modified
    @@ -310,12 +310,84 @@ type PdfPayload = {
     
     type FileResultPayloads = PdfPayload;
     
    +/**
    +/**
    + * Validate that a URL is safe to fetch, blocking SSRF attack vectors.
    + *
    + * Rejects:
    + * - Non-HTTP(S) schemes (file://, ftp://, etc.)
    + * - Private / loopback IPv4 ranges: 127.x, 10.x, 172.16-31.x, 192.168.x
    + * - Link-local IPv4 (169.254.x.x) — used by AWS/GCP/Azure instance metadata
    + * - IPv6 loopback (::1) and unspecified (::)
    + * - Common internal hostnames (localhost, host.docker.internal, etc.)
    + *
    + * Note: does not perform DNS resolution, so DNS-rebinding attacks are not
    + * blocked here; a network-layer proxy or egress firewall is required for that.
    + *
    + * @throws Error with a descriptive message if the URL is disallowed.
    + */
    +function validateFetchUrl(rawUrl: string): void {
    +    let parsed: URL;
    +    try {
    +        parsed = new URL(rawUrl);
    +    } catch {
    +        throw new Error(`Invalid URL: ${rawUrl}`);
    +    }
    +
    +    // Only allow HTTP and HTTPS
    +    if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
    +        throw new Error(`Blocked URL scheme "${parsed.protocol}" — only http: and https: are allowed`);
    +    }
    +
    +    const hostname = parsed.hostname.toLowerCase().replace(/^\[|\]$/g, ''); // strip IPv6 brackets
    +
    +    // Block loopback and unspecified IPv6
    +    if (hostname === '::1' || hostname === '::' || hostname === '0:0:0:0:0:0:0:1') {
    +        throw new Error(`Blocked request to loopback address: ${hostname}`);
    +    }
    +
    +    // Block well-known internal hostnames
    +    const blockedHostnames = new Set([
    +        'localhost',
    +        'host.docker.internal',
    +        'metadata.google.internal',
    +        'metadata.goog',
    +    ]);
    +    if (blockedHostnames.has(hostname)) {
    +        throw new Error(`Blocked request to internal hostname: ${hostname}`);
    +    }
    +
    +    // Block .local mDNS names
    +    if (hostname.endsWith('.local')) {
    +        throw new Error(`Blocked request to mDNS host: ${hostname}`);
    +    }
    +
    +    // Parse dotted-decimal IPv4 to check private/link-local ranges
    +    const ipv4Parts = hostname.split('.');
    +    if (ipv4Parts.length === 4 && ipv4Parts.every(p => /^\d+$/.test(p))) {
    +        const [a, b, c] = ipv4Parts.map(Number);
    +        if (
    +            a === 127 ||                              // 127.0.0.0/8  loopback
    +            a === 10 ||                               // 10.0.0.0/8   private
    +            (a === 172 && b >= 16 && b <= 31) ||     // 172.16-31.x  private
    +            (a === 192 && b === 168) ||               // 192.168.0.0/16 private
    +            (a === 169 && b === 254) ||               // 169.254.0.0/16 link-local (cloud metadata)
    +            (a === 0)                                 // 0.x.x.x      unspecified
    +        ) {
    +            throw new Error(`Blocked request to private/reserved IP address: ${hostname}`);
    +        }
    +    }
    +}
    +
     /**
      * Read file content from a URL
      * @param url URL to fetch content from
      * @returns File content or file result with metadata
      */
     export async function readFileFromUrl(url: string): Promise<FileResult> {
    +    // Validate URL before fetching to prevent SSRF attacks
    +    validateFetchUrl(url);
    +
         // Import the MIME type utilities
         const { isImageFile } = await import('./mime-types.js');
     
    @@ -325,7 +397,9 @@ export async function readFileFromUrl(url: string): Promise<FileResult> {
     
         try {
             const response = await fetch(url, {
    -            signal: controller.signal
    +            signal: controller.signal,
    +            // Disable automatic redirect following to prevent open-redirect → SSRF chains
    +            redirect: 'error',
             });
     
             // Clear the timeout since fetch completed
    @@ -375,9 +449,14 @@ export async function readFileFromUrl(url: string): Promise<FileResult> {
             clearTimeout(timeoutId);
     
             // Return error information instead of throwing
    -        const errorMessage = error instanceof DOMException && error.name === 'AbortError'
    +        const isTimeout = error instanceof DOMException && error.name === 'AbortError';
    +        const isRedirect = error instanceof TypeError
    +            && (error.message.includes('redirect') || error.message.includes('Redirect'));
    +        const errorMessage = isTimeout
                 ? `URL fetch timed out after ${FILE_OPERATION_TIMEOUTS.URL_FETCH}ms: ${url}`
    -            : `Failed to fetch URL: ${error instanceof Error ? error.message : String(error)}`;
    +            : isRedirect
    +                ? `Blocked redirect from ${url} — use the final destination URL directly`
    +                : `Failed to fetch URL: ${error instanceof Error ? error.message : String(error)}`;
     
             throw new Error(errorMessage);
         }
    

Vulnerability mechanics

Root cause

"The readFileFromUrl function did not validate user-supplied URLs, allowing them to point to internal network resources."

Attack vector

An attacker can trigger this vulnerability by providing a crafted URL to the `readFileFromUrl` function. This allows the attacker to make the server send requests to arbitrary internal network locations, such as cloud metadata endpoints or internal APIs, potentially exfiltrating sensitive information or probing the private network [ref_id=1]. The attack can be performed remotely by an unauthenticated user.

Affected code

The vulnerability resides in the `readFileFromUrl` function within the `src/tools/filesystem.ts` file. Specifically, the function directly uses the `url` argument in a `fetch` call without prior validation [patch_id=4550935].

What the fix does

The patch introduces a `validateFetchUrl` function that is called before any network request is made. This function blocks requests to non-HTTP(S) schemes, loopback addresses, private IPv4 ranges, link-local addresses, and known internal hostnames. Additionally, the `fetch` call is configured with `redirect: 'error'` to prevent open-redirect chains that could bypass initial validation and lead to internal resources. This prevents the server from making unintended requests to internal or sensitive endpoints [patch_id=4550935].

Preconditions

  • authNo authentication is required to exploit this vulnerability.
  • networkThe vulnerable server must be reachable over the network.
  • inputThe attacker must be able to control the URL passed to the `readFileFromUrl` function.

Generated on Jun 3, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.