CVE-2026-54617: Launchserver api Path Traversal Vulnerability

CRITICAL
Advisory Identifier: GHSA-5g75-477j-2c2f
CVSS 9.8
CWE-522 CWE-200 CWE-22
Published
Advisory Summary

CVE-2026-54617 is a CRITICAL (CVSS 9.8) path traversal vulnerability (CWE-522: Insufficiently Protected Credentials) affecting Launchserver api libraries in the Maven ecosystem. The issue involves launchserver fileserverhandler has an unauthenticated path traversal issue. Remediation is available in the latest vendor maintenance releases.

CVE-2026-54617 at a Glance

CVE Identifier CVE-2026-54617
GHSA Identifier GHSA-5g75-477j-2c2f
Severity CRITICAL
CVSS v3.1 Base Score 9.8
CWE Classification CWE-522: Insufficiently Protected Credentials
Affected Product Launchserver api
Package Ecosystem Maven
Published Date
Last Updated

Security Impact

CVSS: 9.8

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

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

How to Fix CVE-2026-54617

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

pro.gravit.launcher:launchserver-api fixed: Latest secure release
<dependency>
    <groupId>pro.gravit.launcher</groupId>
    <artifactId>launchserver-api</artifactId>
    <version>Latest secure release</version>
</dependency>
Verify Direct and Transitive Dependencies

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

mvn dependency:tree -Dincludes=pro.gravit.launcher

How to Check if You Are Affected

To determine whether your Java application is affected by CVE-2026-54617, inspect your build dependencies using the Maven Dependency Plugin:

mvn dependency:tree -Dincludes=pro.gravit.launcher

Analyze the terminal output to locate any version of Launchserver api in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than the patched release), your application is affected.

Note: The mvn dependency:tree -Dincludes=pro.gravit.launcher command inspects the resolved dependency graph declared in your project's POM files; it does not perform automated security scanning or inspect runtime dynamic classpaths. Always verify runtime container classpaths and shaded JARs.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-522: Insufficiently Protected Credentials, where the product transmits or stores authentication credentials, but it uses an insecure method that is susceptible to unauthorized interception and/or retrieval. In Launchserver api, 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

### Summary An unauthenticated path traversal in the LaunchServer HTTP file server (`FileServerHandler`) lets any remote actor read **any file** readable by the LaunchServer process (e.g. `../../../../etc/passwd`). This is a generic arbitrary-file-read primitive, so the fix must address the traversal itself, not any specific file. The readable files include the server's own secrets, which turns this from information disclosure into full compromise: the ECDSA private key that signs access JWTs (`.keys/ecdsa_id`), the refresh-token salt (`.keys/legacySalt`), and `LaunchServer.json` (database credentials). With the signing key an attacker mints a valid access token for any account, including admins. That is a full authentication bypass. Pre-auth, default config, port 9274. **Affected:** GravitLauncher LaunchServer ≤ 5.7.11 (the LaunchServer application; the published `pro.gravit.launcher:*-api` Maven artifacts do not contain the vulnerable code). ### Details In `FileServerHandler.channelRead0`: ```java path = Paths.get(IOHelper.getPathFromUrlFragment(uri)).normalize().toString().substring(1); // line 194 File file = base.resolve(path).toFile(); // line 200 - no second normalize() ``` `substring(1)` blindly strips a leading slash, assuming the request-target always starts with `/`. Netty's `HttpServerCodec` accepts a request-target **without** a leading slash verbatim (`decoderResult().isSuccess() == true`). For such a target, `normalize()` cannot collapse the leading `..`, `substring(1)` turns `../` into `./` (leaving the remaining `..`), and `base.resolve(path)`, which is not re-normalized, resolves **outside** `updatesDir`. `file.isHidden()` (line 201) is checked only on the final path component, so targets that don't start with a dot (`ecdsa_id`, `rsa_id`, `legacySalt`, `LaunchServer.json`) are served even with `showHiddenFiles=false`. The file server is enabled by default (`netty.fileServerEnabled=true`) and bound to `0.0.0.0:9274`. No auth handler precedes `FileServerHandler`; `WebSocketServerProtocolHandler("/api")` forwards non-WebSocket / non-`/api` requests down to it, so the attack is a plain HTTP GET (no WebSocket). ### PoC Reproduced on a from-source build of v5.7.11 (Netty 4.2.12). **Must use a raw socket.** curl/browsers/HTTP libraries normalize the path and prepend `/`, hitting the safe branch (false "not reproducible"). ``` printf 'GET ../../.keys/ecdsa_id HTTP/1.1\r\nHost: x\r\n\r\n' | nc <host> 9274 ``` Returns the raw ECDSA private-key bytes. Same for `../../.keys/rsa_id`, `../../.keys/legacySalt`, `../../LaunchServer.json`. `%2e%2e/...` (no leading slash) also works. Depth-robust arbitrary read: `../../../../../../etc/passwd`. Control (confirms the root cause): `GET /../../.keys/ecdsa_id` (WITH leading slash) → 404. Only the no-leading-slash form escapes. ### Impact Unauthenticated remote read of any file the process can access. What that exposes: - `.keys/ecdsa_id`: the key that signs access JWTs. With it, an attacker mints a valid token for any account, including admins, so this is a full authentication bypass. - `.keys/legacySalt`: lets an attacker forge refresh tokens. - `LaunchServer.json`: database credentials. - Any other file readable by the process (config, logs, system files). Deployment note: a normalizing L7 reverse proxy (stock nginx `location / { proxy_pass ...; }`) rejects the no-leading-slash request (400) and collapses leading-slash traversal, blocking the primary vector. But the default bind is `0.0.0.0:9274`, so protection relies on firewalling the backend port; L4/TCP proxies (HAProxy TCP, nginx `stream`, CF Spectrum) and direct exposure remain exploitable. ### Suggested fix 1. Re-`normalize()` after `base.resolve(path)` and verify `resolved.startsWith(base)`. 2. Reject request-targets that don't start with `/` (400). 3. Default-bind to `127.0.0.1`; store `.keys` outside `updatesDir`.

CVE-2026-54617 Affected Launchserver api Versions

1 component(s)
Product / Package Ecosystem Affected Versions Fixed Version
pro.gravit.launcher:launchserver-api
Maven
≤ 5.7.11

References

Frequently Asked Questions

What is CVE-2026-54617?
CVE-2026-54617 is a security vulnerability in Launchserver api involving LaunchServer FileServerHandler has an unauthenticated path traversal issue under CWE-522: Insufficiently Protected Credentials.
Which Launchserver api versions are affected?
Affected versions include releases prior to current release patches across affected packages: pro.gravit.launcher:launchserver-api.
What version fixes CVE-2026-54617?
Upgrading to current release patches (or the latest patched release for your respective branch) resolves the vulnerability.
Is launchserver-api affected?
Yes, pro.gravit.launcher:launchserver-api is affected in releases prior to Latest secure release. Upgrade your dependency to Latest secure release or later.
What is the CVSS score of CVE-2026-54617?
CVE-2026-54617 has a CVSS v3.1 base score of 9.8 (CRITICAL) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with CVE-2026-54617?
CVE-2026-54617 is classified under CWE-522: Insufficiently Protected Credentials (The product transmits or stores authentication credentials, but it uses an insecure method that is susceptible to unauthorized interception and/or retrieval.).
How can I check Maven dependencies for CVE-2026-54617?
Run the dependency tree command: 'mvn dependency:tree -Dincludes=pro.gravit.launcher'. 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-5g75-477j-2c2f",
  "modified" : "2026-07-02T20:49:18Z",
  "published" : "2026-07-02T20:49:18Z",
  "aliases" : [ "CVE-2026-54617" ],
  "summary" : "LaunchServer FileServerHandler has an unauthenticated path traversal issue",
  "details" : "### Summary\nAn unauthenticated path traversal in the LaunchServer HTTP file server (`FileServerHandler`) lets any remote actor read **any file** readable by the LaunchServer process (e.g. `../../../../etc/passwd`). This is a generic arbitrary-file-read primitive, so the fix must address the traversal itself, not any specific file.\n\nThe readable files include the server's own secrets, which turns this from information disclosure into full compromise: the ECDSA private key that signs access JWTs (`.keys/ecdsa_id`), the refresh-token salt (`.keys/legacySalt`), and `LaunchServer.json` (database credentials). With the signing key an attacker mints a valid access token for any account, including admins. That is a full authentication bypass. Pre-auth, default config, port 9274.\n\n**Affected:** GravitLauncher LaunchServer ≤ 5.7.11 (the LaunchServer application; the published `pro.gravit.launcher:*-api` Maven artifacts do not contain the vulnerable code).\n\n### Details\nIn `FileServerHandler.channelRead0`:\n\n```java\npath = Paths.get(IOHelper.getPathFromUrlFragment(uri)).normalize().toString().substring(1); // line 194\nFile file = base.resolve(path).toFile();                                                     // line 200 - no second normalize()\n```\n\n`substring(1)` blindly strips a leading slash, assuming the request-target always starts with `/`. Netty's `HttpServerCodec` accepts a request-target **without** a leading slash verbatim (`decoderResult().isSuccess() == true`). For such a target, `normalize()` cannot collapse the leading `..`, `substring(1)` turns `../` into `./` (leaving the remaining `..`), and `base.resolve(path)`, which is not re-normalized, resolves **outside** `updatesDir`.\n\n`file.isHidden()` (line 201) is checked only on the final path component, so targets that don't start with a dot (`ecdsa_id`, `rsa_id`, `legacySalt`, `LaunchServer.json`) are served even with `showHiddenFiles=false`.\n\nThe file server is enabled by default (`netty.fileServerEnabled=true`) and bound to `0.0.0.0:9274`. No auth handler precedes `FileServerHandler`; `WebSocketServerProtocolHandler(\"/api\")` forwards non-WebSocket / non-`/api` requests down to it, so the attack is a plain HTTP GET (no WebSocket).\n\n### PoC\nReproduced on a from-source build of v5.7.11 (Netty 4.2.12).\n**Must use a raw socket.** curl/browsers/HTTP libraries normalize the path and prepend `/`, hitting the safe branch (false \"not reproducible\").\n\n```\nprintf 'GET ../../.keys/ecdsa_id HTTP/1.1\\r\\nHost: x\\r\\n\\r\\n' | nc <host> 9274\n```\n\nReturns the raw ECDSA private-key bytes. Same for `../../.keys/rsa_id`, `../../.keys/legacySalt`, `../../LaunchServer.json`. `%2e%2e/...` (no leading slash) also works. Depth-robust arbitrary read: `../../../../../../etc/passwd`.\nControl (confirms the root cause): `GET /../../.keys/ecdsa_id` (WITH leading slash) → 404. Only the no-leading-slash form escapes.\n\n### Impact\nUnauthenticated remote read of any file the process can access. What that exposes:\n- `.keys/ecdsa_id`: the key that signs access JWTs. With it, an attacker mints a valid token for any account, including admins, so this is a full authentication bypass.\n- `.keys/legacySalt`: lets an attacker forge refresh tokens.\n- `LaunchServer.json`: database credentials.\n- Any other file readable by the process (config, logs, system files).\n\nDeployment note: a normalizing L7 reverse proxy (stock nginx `location / { proxy_pass ...; }`) rejects the no-leading-slash request (400) and collapses leading-slash traversal, blocking the primary vector. But the default bind is `0.0.0.0:9274`, so protection relies on firewalling the backend port; L4/TCP proxies (HAProxy TCP, nginx `stream`, CF Spectrum) and direct exposure remain exploitable.\n\n### Suggested fix\n1. Re-`normalize()` after `base.resolve(path)` and verify `resolved.startsWith(base)`.\n2. Reject request-targets that don't start with `/` (400).\n3. Default-bind to `127.0.0.1`; store `.keys` outside `updatesDir`.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Maven",
      "name" : "pro.gravit.launcher:launchserver-api"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "last_affected" : "5.7.11"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/GravitLauncher/Launcher/security/advisories/GHSA-5g75-477j-2c2f"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/GravitLauncher/Launcher"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-200", "CWE-22", "CWE-522" ],
    "severity" : "CRITICAL",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-02T20:49:18Z",
    "nvd_published_at" : null
  }
}