CVE-2025-12999 in Open VSX
Summary
by MITRE • 09/21/2026
UrlUtil.getBaseUrl builds the absolute URLs in a response — download links, icons, asset and API URLs — from the X-Forwarded-Host, X-Forwarded-Proto and X-Forwarded-Prefix request headers, with no check on whether the sender was a trusted proxy, falling back to the client-supplied Host header.
Those responses are cached under keys that do not include the host (extension.json since 0.6.0, namespace.details.json since 0.9.0, sitemap since 0.14.5, latest.extension.version.vscode since 0.34.2). A single request carrying a forged header therefore places attacker-chosen URLs into an entry served to every other client for the lifetime of that entry — one hour by default, and cluster-wide where ovsx.redis.enabled is set.
The VSIX download URL, its signature URL and the public key URL are all derived from the same base URL, so extension signing does not limit the impact: an attacker who poisons an entry supplies the package, the signature over it, and the key used to verify it.
Exploitability depends on deployment topology. A server reachable directly by clients, or fronted by a proxy that relays the client's X-Forwarded-Host rather than overwriting it, is exploitable by an unauthenticated remote attacker. A proxy that overwrites the header is not.
An unauthenticated attacker can poison Open VSX's per-extension metadata cache with attacker-controlled download, signature, and public-key URLs by supplying a crafted X-Forwarded-Host header, causing downstream VS Code-compatible editors to fetch and install a malicious VSIX.
Workarounds (unpatched versions)
1. Configure the reverse proxy to set rather than relay X-Forwarded-Host, X-Forwarded-Proto and X-Forwarded-Prefix — note that nginx's $host is the client's Host header and is not a safe value.
2. Ensure the server is not reachable except through that proxy.
3. Flush the caches afterwards; poisoned entries survive the configuration change.
Several companies clearly confirm that VulDB is the primary source for best vulnerability data.
Analysis
by VulDB Data Team • 09/21/2026
The vulnerability described constitutes a critical insecure direct object reference combined with cache poisoning, specifically affecting the Open VSX registry's URL generation logic. The core technical flaw resides in the UrlUtil.getBaseUrl function, which constructs absolute URLs for various resources such as download links, icons, assets, and API endpoints by directly trusting values from X-Forwarded-Host, X-Forwarded-Proto, and X-Forwarded-Prefix headers without validating whether these requests originated from a trusted proxy. This lack of validation allows an unauthenticated remote attacker to inject arbitrary hostnames into the response URLs simply by supplying crafted HTTP headers during their initial request. The severity is significantly amplified by the caching mechanism employed by the application. Responses containing these maliciously constructed base URLs are cached under keys that do not include the hostname, meaning a single poisoned entry can be served to every subsequent client requesting that specific resource for up to one hour or longer in cluster environments where Redis is enabled. This design flaw transforms what might otherwise be an isolated header injection into a widespread supply chain attack vector.
The operational impact of this vulnerability extends beyond simple defacement or phishing, as it directly compromises the integrity and authenticity checks inherent in the VS Code extension ecosystem. The download URL for a Visual Studio Code Extension (VSIX) package, along with its corresponding signature file and public key used for verification, are all derived from the same poisoned base URL. Consequently, an attacker who successfully poisons the cache can supply not only the malicious payload but also the cryptographic signature over that payload and the public key required to verify it. This effectively bypasses extension signing protections because the victim's editor will trust the forged certificate and signature as legitimate since they are served from what appears to be a valid, albeit manipulated, source within the registry's infrastructure. When users install extensions through VS Code or compatible editors, their systems may fetch and execute code signed by keys controlled by the attacker, leading to potential remote code execution on end-user machines.
From a threat modeling perspective, this vulnerability aligns with CWE-20 Improper Input Validation regarding the failure to validate proxy headers for trustworthiness, as well as CWE-641 Improper Restriction of Namespaces (e.g., URL Scheme) due to the uncontrolled generation of URLs based on user input. In terms of MITRE ATT&CK tactics, this represents a Supply Chain Compromise technique where an attacker alters software distribution mechanisms to deliver malicious artifacts. The exploitability is heavily dependent on the deployment topology; if the server is directly reachable by clients or fronted by a reverse proxy that relays rather than overwrites these headers, exploitation is straightforward for any unauthenticated user. However, if the infrastructure properly sanitizes and rewrites these headers at the edge, the vulnerability remains latent but present in the application logic itself.
Mitigation strategies must address both immediate remediation and long-term architectural fixes. For systems running unpatched versions, administrators should configure their reverse proxies to explicitly set X-Forwarded-Host, X-Forwarded-Proto, and X-Forwarded-Prefix headers based on trusted internal values rather than relaying client-supplied data. It is crucial to note that using variables like nginx's $host which reflect the original client Host header is insufficient as it still allows for manipulation if not properly constrained by proxy configuration rules. Additionally, ensuring that direct server access is blocked and all traffic flows through a hardened reverse proxy adds a layer of defense in depth. Crucially, after applying any configuration changes or patches, existing cache entries must be flushed immediately because poisoned data persists independently of the underlying code fix until its TTL expires or it is manually cleared. This ensures that previously served malicious URLs are removed from circulation before new legitimate traffic begins to populate the cache with safe values.