Skip to content

Coder: Unauthenticated SSRF via Azure Instance Identity Endpoint

Moderate severity GitHub Reviewed Published May 13, 2026 in coder/coder • Updated May 19, 2026

Package

gomod github.com/coder/coder (Go)

Affected versions

<= 0.27.3

Patched versions

None
gomod github.com/coder/coder/v2 (Go)
>= 2.33.0-rc.0, < 2.33.3
>= 2.32.0-rc.0, < 2.32.2
>= 2.31.0, < 2.31.12
>= 2.30.0, < 2.30.8
>= 2.29.0, < 2.29.13
< 2.24.5
2.33.3
2.32.2
2.31.12
2.30.8
2.29.13
2.24.5

Description

Summary

Unauthenticated semi-blind Server-Side Request Forgery (SSRF) via the Azure instance identity endpoint (POST /api/v2/workspaceagents/azure-instance-identity). An external attacker can force the Coder server to issue HTTP GET requests to arbitrary internal or external hosts by submitting a crafted PKCS#7 signature. The server does not return the target's response body, but error messages in the API response reveal whether the target is reachable and what type of failure occurred.

Details

The POST /api/v2/workspaceagents/azure-instance-identity endpoint accepts a PKCS#7 signature without authentication. During certificate chain verification, azureidentity.Validate() iterates over the signer certificate's IssuingCertificateURL extension and fetches each URL using http.DefaultClient with no host restriction, no private-IP blocking, and no response-size limit.

An attacker crafts a self-signed certificate whose Common Name matches *.metadata.azure.com (passing the allowedSigners regex) and whose IssuingCertificateURL points to an attacker-chosen target. The server fetches that URL and feeds the response body into x509.ParseCertificate. The parsed result is discarded, but the wrapped error string is returned verbatim in the JSON response via Detail: err.Error(). Connection-level errors ("connection refused", "i/o timeout", DNS failures) and certificate-parse errors give the attacker enough signal to infer host reachability and port state without seeing the actual response content.

Root causes:

  1. No allowlist on IssuingCertificateURL hosts. Any URL was accepted.
  2. http.DefaultClient was used. It follows redirects and connects to private, link-local, and loopback addresses.
  3. Unbounded io.ReadAll on the response body (memory exhaustion vector).
  4. Raw err.Error() was returned in the JSON response, leaking internal HTTP client errors to the caller.

Impact

This is a semi-blind SSRF: the server makes the outbound request but the HTTP response body is consumed by x509.ParseCertificate and never returned to the attacker.

  • Internal network reconnaissance. The attacker can map internal hosts and ports by observing error differentiation in the API response: "connection refused" (port closed), "i/o timeout" (host unreachable or firewalled), DNS failure (host does not exist), or certificate-parse error (port open and responding). This enables systematic scanning of the internal network from the Coder server's vantage point.
  • Requests to sensitive endpoints. The server can be directed to hit cloud metadata services (e.g. http://169.254.169.254/), internal admin interfaces, or other services. The attacker cannot read the response content, but the request itself may have side effects depending on the target.
  • Error-based information disclosure. Wrapped Go HTTP client errors in the Detail field expose internal hostnames, IP addresses, port numbers, and network topology details.
  • Memory exhaustion. The unbounded io.ReadAll on the response body allows an attacker to point IssuingCertificateURL at a large resource, forcing the server to buffer it entirely in memory.

Patches

Fixed in #25274 (commit 57b11d405):

The fix was backported to all supported release lines:

Release line Patched version
2.33 v2.33.3
2.32 v2.32.2
2.31 v2.31.12
2.30 v2.30.8
2.29 v2.29.13
2.24 (ESR) v2.24.5

Workarounds

If the Azure identity-auth mechanism is not being used then restrict access to the corresponding endpoint (/api/v2/workspaceagents/azure-instance-identity) using ingress firewall and/or proxy ACLs.

Recognition

We'd like to thank Ben Tran of calif.io and Anthropic's Security Team (ANT-2026-22447) for independently disclosing this issue!

References

@jdomeracki-coder jdomeracki-coder published to coder/coder May 13, 2026
Published to the GitHub Advisory Database May 19, 2026
Reviewed May 19, 2026
Last updated May 19, 2026

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
Low
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N

EPSS score

Weaknesses

Server-Side Request Forgery (SSRF)

The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination. Learn more on MITRE.

CVE ID

CVE-2026-45796

GHSA ID

GHSA-686c-7vgv-v3fx

Source code

Credits

Loading Checking history
See something to contribute? Suggest improvements for this vulnerability.