GHSA-WQ4W-VWVQ-Q3X9
Vulnerability from github – Published: 2026-10-15 20:14 – Updated: 2026-10-15 20:14Summary
Standalone short tokens issued for WebSocket and explicit-token authentication can survive administrative revocation in cache. If the same account is later re-enabled before the cache entry expires, the deleted short token becomes valid again.
Details
GenerateShortToken() creates an AuthToken row that contains only ShortToken and no long Token. DeleteUserTokens() removes database rows, but when clearing caches it only invalidates entries where authToken.Token != "". This leaves standalone short-token cache entries behind. GetTokenUserByShortToken() checks that cache first and then loads the user by ID, so the stale short token becomes usable again if the account status is restored to true.
Relevant code paths: - internal/user/user.go - internal/user/user.go - internal/user/user.go - api/user/short_token.go - internal/middleware/middleware.go
PoC
This was verfied locally in an isolated environment with a temporary package-level harness that exercised the real token issuance, revocation, cache, and re-authentication paths.
What the executed test did:
1. Created an enabled user in a temporary SQLite database.
2. Called the real GenerateShortToken(user.ID) function to issue a standalone short token.
3. Verified that the token authenticated successfully and was present in the short-token cache.
4. Disabled the user and called the real DeleteUserTokens(user.ID) function.
5. Verified that the database token rows were removed.
6. Verified that the short-token cache entry still existed after DeleteUserTokens.
7. Re-enabled the same user.
8. Reused the previously deleted short token via the real GetTokenUserByShortToken() path and observed successful authentication.
Observed result from the actual local verification: - The database token rows were removed during revocation. - The short-token cache entry remained present. - Re-enabling the user restored successful authentication through the stale short token.
Impact
Any deployment using standalone short tokens is affected. If a short token is stolen, administrative disable/delete-token handling may not fully revoke it. Re-enabling the account within the cache lifetime restores access for the stale token to any HTTP or WebSocket routes that accept short-token authentication.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/0xJacky/Nginx-UI"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.9.10-0.20260703131214-23d1934099b0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-84321"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-15T20:14:01Z",
"nvd_published_at": "2026-10-12T21:17:22Z",
"severity": "MODERATE"
},
"details": "### Summary\nStandalone short tokens issued for WebSocket and explicit-token authentication can survive administrative revocation in cache. If the same account is later re-enabled before the cache entry expires, the deleted short token becomes valid again.\n\n### Details\n`GenerateShortToken()` creates an `AuthToken` row that contains only `ShortToken` and no long `Token`. `DeleteUserTokens()` removes database rows, but when clearing caches it only invalidates entries where `authToken.Token != \"\"`. This leaves standalone short-token cache entries behind. `GetTokenUserByShortToken()` checks that cache first and then loads the user by ID, so the stale short token becomes usable again if the account status is restored to `true`.\n\nRelevant code paths:\n- [internal/user/user.go](/home/kali/Desktop/bounty/nginx-ui/internal/user/user.go:43)\n- [internal/user/user.go](/home/kali/Desktop/bounty/nginx-ui/internal/user/user.go:118)\n- [internal/user/user.go](/home/kali/Desktop/bounty/nginx-ui/internal/user/user.go:204)\n- [api/user/short_token.go](/home/kali/Desktop/bounty/nginx-ui/api/user/short_token.go:13)\n- [internal/middleware/middleware.go](/home/kali/Desktop/bounty/nginx-ui/internal/middleware/middleware.go:82)\n\n### PoC\nThis was verfied locally in an isolated environment with a temporary package-level harness that exercised the real token issuance, revocation, cache, and re-authentication paths.\n\nWhat the executed test did:\n1. Created an enabled user in a temporary SQLite database.\n2. Called the real `GenerateShortToken(user.ID)` function to issue a standalone short token.\n3. Verified that the token authenticated successfully and was present in the short-token cache.\n4. Disabled the user and called the real `DeleteUserTokens(user.ID)` function.\n5. Verified that the database token rows were removed.\n6. Verified that the short-token cache entry still existed after `DeleteUserTokens`.\n7. Re-enabled the same user.\n8. Reused the previously deleted short token via the real `GetTokenUserByShortToken()` path and observed successful authentication.\n\nObserved result from the actual local verification:\n- The database token rows were removed during revocation.\n- The short-token cache entry remained present.\n- Re-enabling the user restored successful authentication through the stale short token.\n\n### Impact\nAny deployment using standalone short tokens is affected. If a short token is stolen, administrative disable/delete-token handling may not fully revoke it. Re-enabling the account within the cache lifetime restores access for the stale token to any HTTP or WebSocket routes that accept short-token authentication.",
"id": "GHSA-wq4w-vwvq-q3x9",
"modified": "2026-10-15T20:14:01Z",
"published": "2026-10-15T20:14:01Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-wq4w-vwvq-q3x9"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-84321"
},
{
"type": "WEB",
"url": "https://github.com/0xJacky/nginx-ui/commit/23d1934099b05b2a01589b48129dc3d3159d91c2"
},
{
"type": "PACKAGE",
"url": "https://github.com/0xJacky/nginx-ui"
},
{
"type": "WEB",
"url": "https://github.com/0xJacky/nginx-ui/releases/tag/v2.4.1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Nginx UI: Standalone short tokens survive administrative revocation in cache and authenticate again after account re-enable"
}
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.