CWE-639
AllowedAuthorization Bypass Through User-Controlled Key
Abstraction: Base · Status: Incomplete
The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.
3256 vulnerabilities reference this CWE, most recent first.
GHSA-Q6W3-HPFV-RG36
Vulnerability from github – Published: 2026-05-29 22:05 – Updated: 2026-05-29 22:05Summary
modules/documents-files.php mode file_rename_save shares the same root-cause shape as the cross-folder move bug (05-documents-cross-folder-move-idor.md): the top-level rights check at lines 79-89 validates hasUploadRight() on the URL parameter folder_uuid, but the rename operation acts on file_uuid — a separate URL parameter — without re-checking the folder that actually contains the file. DocumentsService::renameFile() resolves the target file via getFileForDownload() (which permits view-readable files) but does not require upload right on the file's source folder. Result: a user with upload right on any folder A can rename a file in folder B as long as they can view it. They can also overwrite the file's description.
Details
Vulnerable Code
modules/documents-files.php:79-89 — top-level check binds to URL folder_uuid:
if ($getMode != 'list' && $getMode != 'download') {
$folder = new Folder($gDb);
$folder->getFolderForDownload($getFolderUUID);
if (!$folder->hasUploadRight()) {
$gMessage->show($gL10n->get('SYS_NO_RIGHTS'));
}
}
src/Documents/Service/DocumentsService.php:272-315 — renameFile() resolves the file via getFileForDownload() (view-only) and never re-verifies upload right on the file's parent:
public function renameFile(string $fileUUID, string $newName, string $newDescription): array
{
$file = new File($this->db);
$file->getFileForDownload($fileUUID); // <-- view rights, not upload
...
$oldFile = $file->getFullFilePath();
$newFile = $newName . '.' . pathinfo($oldFile, PATHINFO_EXTENSION);
$newPath = pathinfo($oldFile, PATHINFO_DIRNAME) . '/';
FileSystemUtils::moveFile($oldFile, $newPath . $newFile);
$file->setValue('fil_name', $newFile);
$file->setValue('fil_description', $newDescription);
$file->save();
...
}
getFileForDownload() enforces only the download (read) ACL on the file's folder. There is no hasUploadRight() check anywhere in the rename path. The actual file remains in its original folder; only its name and description change. This means the modified metadata is visible to every other user who legitimately has download rights on that folder, while the modification itself was performed by a user who has no edit right on it.
Exploitation Primitive
- Attacker user
lowuserholdsfolder_uploadonpublic_uploadable(UUIDc41a99c0-…). They have view (download) rights onview_only_public(UUID21b417e2-…,fol_public=1) but no upload/edit right there. The folder containsadmin_announcement.txt(UUIDaaae5edd-…). - Render the rename form with a
folder_uuidof a folder lowuser CAN upload to and afile_uuidof the target file:GET /modules/documents-files.php?mode=file_rename&folder_uuid=c41a99c0-…&file_uuid=aaae5edd-…The top-level rights check at line 85 sees the public-uploadable folder and passes. - Submit rename:
POST /modules/documents-files.php?mode=file_rename_save&folder_uuid=c41a99c0-…&file_uuid=aaae5edd-…withadm_csrf_token=<from step 2>,adm_new_name=hijacked_announcement,adm_new_description=Hijacked!. Server replies{"status":"success"}.adm_files:fil_fol_id=7(still the originalview_only_public),fil_name='hijacked_announcement.txt',fil_description='Hijacked!'. On disk:admin_announcement.txtis renamed tohijacked_announcement.txtin its original folder.
PoC
Captured live against HEAD c5cde53 (mariadb on 127.0.0.1:3399, php on 127.0.0.1:8085):
$ curl -sb $cookie \
"http://127.0.0.1:8085/modules/documents-files.php?mode=file_rename&folder_uuid=c41a99c0-…&file_uuid=aaae5edd-…"
# form rendered, CSRF token X added to session
$ curl -sb $cookie -X POST \
"http://127.0.0.1:8085/modules/documents-files.php?mode=file_rename_save&folder_uuid=c41a99c0-…&file_uuid=aaae5edd-…" \
-d "adm_csrf_token=X&adm_new_name=hijacked_announcement&adm_new_description=Hijacked%21"
{"status":"success", …}
$ mariadb -h 127.0.0.1 -P 3399 -u admidio -p… admidio \
-e "SELECT fil_fol_id, fil_name, fil_description FROM adm_files WHERE fil_uuid='aaae5edd-…';"
fil_fol_id fil_name fil_description
7 hijacked_announcement.txt Hijacked!
The folder ID fil_fol_id=7 is view_only_public — the folder that lowuser had no upload right on. The change was applied as if lowuser were authorised.
Impact
A user with the most basic Documents permission — upload to a single folder — can rename and overwrite descriptions of files in any other folder they can read. Confidentiality is unaffected (the actor already had download rights on the affected files), but integrity is broken across folder boundaries. Concretely:
- Defacement of public announcements / policies / circulars. A regular member can replace
admin_announcement.txtwithhijacked_announcement.txtand a description that misrepresents the content. Other readers see the malicious metadata. - Renaming-to-confuse. Files can be renamed to identifiers that imply different content (
board_minutes_2025-Q4.pdf→board_minutes_DRAFT-do-not-distribute.pdf). - Description-as-XSS-vector (downstream): if any view path treats
fil_descriptionas raw HTML, this becomes a stored XSS by a low-privilege user; absent that, it is plain content tampering.
The CVSS reflects: PR:L (uploader on any folder), S:U (stays inside Admidio's authorisation model), C:N because the actor already had read access, I:H because the file's identity is changed for every other reader, A:N because files are not deleted.
Recommended Fix
DocumentsService::renameFile() must check upload right on the file's source folder before mutating it:
// src/Documents/Service/DocumentsService.php
public function renameFile(string $fileUUID, string $newName, string $newDescription): array
{
$file = new File($this->db);
$file->getFileForDownload($fileUUID);
// verify the current user has upload (write) right on the file's parent folder,
// not just download right (which getFileForDownload enforces)
$sourceFolder = new Folder($this->db);
$sourceFolder->readData($file->getValue('fil_fol_id'));
if (!$sourceFolder->hasUploadRight()) {
throw new Exception('SYS_NO_RIGHTS');
}
...
}
Equivalently, in modules/documents-files.php case 'file_rename_save', resolve the file's parent folder and check hasUploadRight() against it before calling the service. The same fix should be applied to other documents-files modes that take a file_uuid independently of folder_uuid.
Related
This bug shares its root cause with 05-documents-cross-folder-move-idor.md — both flow from the top-level rights check at lines 79-89 binding to URL folder_uuid rather than the actual file's parent. A single fix to enforce source-folder upload right inside File::moveToFolder() and DocumentsService::renameFile() (and any other operations on file_uuid) closes both.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 5.0.9"
},
"package": {
"ecosystem": "Packagist",
"name": "admidio/admidio"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.0.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-47230"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-29T22:05:47Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\n`modules/documents-files.php` mode `file_rename_save` shares the same root-cause shape as the cross-folder move bug (`05-documents-cross-folder-move-idor.md`): the top-level rights check at lines 79-89 validates `hasUploadRight()` on the URL parameter `folder_uuid`, but the rename operation acts on `file_uuid` \u2014 a separate URL parameter \u2014 without re-checking the folder that actually contains the file. `DocumentsService::renameFile()` resolves the target file via `getFileForDownload()` (which permits view-readable files) but does not require upload right on the file\u0027s source folder. Result: a user with upload right on any folder A can rename a file in folder B as long as they can view it. They can also overwrite the file\u0027s description.\n\n## Details\n\n### Vulnerable Code\n\n`modules/documents-files.php:79-89` \u2014 top-level check binds to URL `folder_uuid`:\n\n```php\nif ($getMode != \u0027list\u0027 \u0026\u0026 $getMode != \u0027download\u0027) {\n $folder = new Folder($gDb);\n $folder-\u003egetFolderForDownload($getFolderUUID);\n if (!$folder-\u003ehasUploadRight()) {\n $gMessage-\u003eshow($gL10n-\u003eget(\u0027SYS_NO_RIGHTS\u0027));\n }\n}\n```\n\n`src/Documents/Service/DocumentsService.php:272-315` \u2014 `renameFile()` resolves the file via `getFileForDownload()` (view-only) and never re-verifies upload right on the file\u0027s parent:\n\n```php\npublic function renameFile(string $fileUUID, string $newName, string $newDescription): array\n{\n $file = new File($this-\u003edb);\n $file-\u003egetFileForDownload($fileUUID); // \u003c-- view rights, not upload\n ...\n $oldFile = $file-\u003egetFullFilePath();\n $newFile = $newName . \u0027.\u0027 . pathinfo($oldFile, PATHINFO_EXTENSION);\n $newPath = pathinfo($oldFile, PATHINFO_DIRNAME) . \u0027/\u0027;\n FileSystemUtils::moveFile($oldFile, $newPath . $newFile);\n\n $file-\u003esetValue(\u0027fil_name\u0027, $newFile);\n $file-\u003esetValue(\u0027fil_description\u0027, $newDescription);\n $file-\u003esave();\n ...\n}\n```\n\n`getFileForDownload()` enforces only the *download* (read) ACL on the file\u0027s folder. There is no `hasUploadRight()` check anywhere in the rename path. The actual file remains in its original folder; only its name and description change. This means the modified metadata is visible to every other user who legitimately has download rights on that folder, while the modification itself was performed by a user who has no edit right on it.\n\n### Exploitation Primitive\n\n1. Attacker user `lowuser` holds `folder_upload` on `public_uploadable` (UUID `c41a99c0-\u2026`). They have *view* (download) rights on `view_only_public` (UUID `21b417e2-\u2026`, `fol_public=1`) but no upload/edit right there. The folder contains `admin_announcement.txt` (UUID `aaae5edd-\u2026`).\n2. Render the rename form with a `folder_uuid` of a folder lowuser CAN upload to and a `file_uuid` of the target file:\n `GET /modules/documents-files.php?mode=file_rename\u0026folder_uuid=c41a99c0-\u2026\u0026file_uuid=aaae5edd-\u2026`\n The top-level rights check at line 85 sees the public-uploadable folder and passes.\n3. Submit rename:\n `POST /modules/documents-files.php?mode=file_rename_save\u0026folder_uuid=c41a99c0-\u2026\u0026file_uuid=aaae5edd-\u2026` with `adm_csrf_token=\u003cfrom step 2\u003e`, `adm_new_name=hijacked_announcement`, `adm_new_description=Hijacked!`.\n Server replies `{\"status\":\"success\"}`. `adm_files`: `fil_fol_id=7` (still the original `view_only_public`), `fil_name=\u0027hijacked_announcement.txt\u0027`, `fil_description=\u0027Hijacked!\u0027`. On disk: `admin_announcement.txt` is renamed to `hijacked_announcement.txt` in its original folder.\n\n## PoC\n\nCaptured live against HEAD `c5cde53` (mariadb on `127.0.0.1:3399`, php on `127.0.0.1:8085`):\n\n```\n$ curl -sb $cookie \\\n \"http://127.0.0.1:8085/modules/documents-files.php?mode=file_rename\u0026folder_uuid=c41a99c0-\u2026\u0026file_uuid=aaae5edd-\u2026\"\n# form rendered, CSRF token X added to session\n\n$ curl -sb $cookie -X POST \\\n \"http://127.0.0.1:8085/modules/documents-files.php?mode=file_rename_save\u0026folder_uuid=c41a99c0-\u2026\u0026file_uuid=aaae5edd-\u2026\" \\\n -d \"adm_csrf_token=X\u0026adm_new_name=hijacked_announcement\u0026adm_new_description=Hijacked%21\"\n{\"status\":\"success\", \u2026}\n\n$ mariadb -h 127.0.0.1 -P 3399 -u admidio -p\u2026 admidio \\\n -e \"SELECT fil_fol_id, fil_name, fil_description FROM adm_files WHERE fil_uuid=\u0027aaae5edd-\u2026\u0027;\"\nfil_fol_id fil_name fil_description\n7 hijacked_announcement.txt Hijacked!\n```\n\nThe folder ID `fil_fol_id=7` is `view_only_public` \u2014 the folder that `lowuser` had no upload right on. The change was applied as if `lowuser` were authorised.\n\n## Impact\n\nA user with the most basic Documents permission \u2014 upload to a single folder \u2014 can rename and overwrite descriptions of files in any other folder they can read. Confidentiality is unaffected (the actor already had download rights on the affected files), but integrity is broken across folder boundaries. Concretely:\n\n* **Defacement of public announcements / policies / circulars.** A regular member can replace `admin_announcement.txt` with `hijacked_announcement.txt` and a description that misrepresents the content. Other readers see the malicious metadata.\n* **Renaming-to-confuse.** Files can be renamed to identifiers that imply different content (`board_minutes_2025-Q4.pdf` \u2192 `board_minutes_DRAFT-do-not-distribute.pdf`).\n* **Description-as-XSS-vector** (downstream): if any view path treats `fil_description` as raw HTML, this becomes a stored XSS by a low-privilege user; absent that, it is plain content tampering.\n\nThe CVSS reflects: `PR:L` (uploader on any folder), `S:U` (stays inside Admidio\u0027s authorisation model), `C:N` because the actor already had read access, `I:H` because the file\u0027s identity is changed for every other reader, `A:N` because files are not deleted.\n\n## Recommended Fix\n\n`DocumentsService::renameFile()` must check upload right on the file\u0027s source folder before mutating it:\n\n```php\n// src/Documents/Service/DocumentsService.php\npublic function renameFile(string $fileUUID, string $newName, string $newDescription): array\n{\n $file = new File($this-\u003edb);\n $file-\u003egetFileForDownload($fileUUID);\n\n // verify the current user has upload (write) right on the file\u0027s parent folder,\n // not just download right (which getFileForDownload enforces)\n $sourceFolder = new Folder($this-\u003edb);\n $sourceFolder-\u003ereadData($file-\u003egetValue(\u0027fil_fol_id\u0027));\n if (!$sourceFolder-\u003ehasUploadRight()) {\n throw new Exception(\u0027SYS_NO_RIGHTS\u0027);\n }\n ...\n}\n```\n\nEquivalently, in `modules/documents-files.php` `case \u0027file_rename_save\u0027`, resolve the file\u0027s parent folder and check `hasUploadRight()` against it before calling the service. The same fix should be applied to other documents-files modes that take a `file_uuid` independently of `folder_uuid`.\n\n## Related\n\nThis bug shares its root cause with `05-documents-cross-folder-move-idor.md` \u2014 both flow from the top-level rights check at lines 79-89 binding to URL `folder_uuid` rather than the actual file\u0027s parent. A single fix to enforce source-folder upload right inside `File::moveToFolder()` and `DocumentsService::renameFile()` (and any other operations on file_uuid) closes both.",
"id": "GHSA-q6w3-hpfv-rg36",
"modified": "2026-05-29T22:05:47Z",
"published": "2026-05-29T22:05:47Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/Admidio/admidio/security/advisories/GHSA-q6w3-hpfv-rg36"
},
{
"type": "PACKAGE",
"url": "https://github.com/Admidio/admidio"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Admidio: IDOR in documents-files.php allows cross-folder file rename and description changes by unauthorized uploaders"
}
GHSA-Q6W5-JG5Q-47VG
Vulnerability from github – Published: 2024-01-12 20:27 – Updated: 2024-01-12 22:33Impact
Unauthorized access or privilege escalation due to a logic flaw in auth() in the App Router or getAuth() in the Pages Router.
Affected Versions
All applications that that use @clerk/nextjs versions in the range of >= 4.7.0,< 4.29.3 in a Next.js backend to authenticate API Routes, App Router, or Route handlers. Specifically, those that call auth() in the App Router or getAuth() in the Pages Router. Only the @clerk/nextjs SDK is impacted. Other SDKs, including other Javascript-based SDKs, are not impacted.
Patches
Fix included in @clerk/nextjs@4.29.3.
References
- https://clerk.com/changelog/2024-01-12
- https://github.com/clerk/javascript/releases/tag/%40clerk%2Fnextjs%404.29.3
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@clerk/nextjs"
},
"ranges": [
{
"events": [
{
"introduced": "4.7.0"
},
{
"fixed": "4.29.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-22206"
],
"database_specific": {
"cwe_ids": [
"CWE-284",
"CWE-287",
"CWE-639"
],
"github_reviewed": true,
"github_reviewed_at": "2024-01-12T20:27:29Z",
"nvd_published_at": "2024-01-12T20:15:47Z",
"severity": "CRITICAL"
},
"details": "### Impact\nUnauthorized access or privilege escalation due to a logic flaw in `auth()` in the App Router or `getAuth()` in the Pages Router.\n\n### Affected Versions\nAll applications that that use `@clerk/nextjs` versions in the range of `\u003e= 4.7.0`,`\u003c 4.29.3` in a Next.js backend to authenticate API Routes, App Router, or Route handlers. Specifically, those that call `auth()` in the App Router or `getAuth()` in the Pages Router. Only the `@clerk/nextjs` SDK is impacted. Other SDKs, including other Javascript-based SDKs, are not impacted.\n\n### Patches\nFix included in `@clerk/nextjs@4.29.3`.\n\n### References\n- https://clerk.com/changelog/2024-01-12\n- https://github.com/clerk/javascript/releases/tag/%40clerk%2Fnextjs%404.29.3",
"id": "GHSA-q6w5-jg5q-47vg",
"modified": "2024-01-12T22:33:02Z",
"published": "2024-01-12T20:27:29Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/clerk/javascript/security/advisories/GHSA-q6w5-jg5q-47vg"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-22206"
},
{
"type": "WEB",
"url": "https://clerk.com/changelog/2024-01-12"
},
{
"type": "PACKAGE",
"url": "https://github.com/clerk/javascript"
},
{
"type": "WEB",
"url": "https://github.com/clerk/javascript/releases/tag/%40clerk%2Fnextjs%404.29.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "@clerk/nextjs auth() and getAuth() methods vulnerable to insecure direct object reference (IDOR) "
}
GHSA-Q6XH-RW6Q-PCC2
Vulnerability from github – Published: 2022-04-26 00:00 – Updated: 2022-05-06 00:01The DW Question & Answer Pro WordPress plugin through 1.3.4 does not check that the comment to edit belongs to the user making the request, allowing any user to edit other comments.
{
"affected": [],
"aliases": [
"CVE-2021-24800"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-04-25T16:16:00Z",
"severity": "MODERATE"
},
"details": "The DW Question \u0026 Answer Pro WordPress plugin through 1.3.4 does not check that the comment to edit belongs to the user making the request, allowing any user to edit other comments.",
"id": "GHSA-q6xh-rw6q-pcc2",
"modified": "2022-05-06T00:01:15Z",
"published": "2022-04-26T00:00:41Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-24800"
},
{
"type": "WEB",
"url": "https://wpscan.com/vulnerability/cd37ca81-d683-4955-bc97-60204cb9c346"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-Q6XX-5VR8-P898
Vulnerability from github – Published: 2026-06-26 22:31 – Updated: 2026-06-26 22:31Summary
In nezha v1.14.13–v1.14.14 and v2.0.0–v2.0.9, the WebSocket endpoints GET /ws/terminal/:id and GET /ws/file/:id authenticate the caller only by the presence of a valid stream UUID, with no ownership check tying that UUID to the user who created the stream. Any authenticated dashboard user (including a RoleMember) who learns a live stream UUID can attach to the session and gain interactive shell access or full file-manager control on the target server — i.e. cross-tenant RCE.
This was silently fixed in commit 6661d6a (2026-05-18, shipped in v2.0.10). At submission time no public CVE/GHSA covers this fix, so operators of v1.14.x and pre-v2.0.10 v2.x deployments have no signal that they are running vulnerable code.
Details
Stream allocation — service/rpc/io_stream.go (v2.0.9):
func (s *NezhaHandler) CreateStream(streamId string) {
s.ioStreamMutex.Lock()
defer s.ioStreamMutex.Unlock()
s.ioStreams[streamId] = &ioStreamContext{
userIoConnectCh: make(chan struct{}),
agentIoConnectCh: make(chan struct{}),
}
}
No creator is bound to the stream.
Stream attach — cmd/dashboard/controller/terminal.go (v2.0.9):
// @Router /ws/terminal/{id} [get]
func terminalStream(c *gin.Context) (any, error) {
streamId := c.Param("id")
if _, err := rpc.NezhaHandlerSingleton.GetStream(streamId); err != nil {
return nil, err
}
defer rpc.NezhaHandlerSingleton.CloseStream(streamId)
// ... WebSocket upgrade and bidirectional pipe ...
}
The only authorization check is GetStream(streamId) — "does this UUID exist in the in-memory map". getUid(c) is never compared against the user who called createTerminal. The same pattern is present in fmStream(c) in cmd/dashboard/controller/fm.go.
Where the UUID leaks:
createTerminal returns the UUID to the legitimate client, which then opens wss://<dashboard>/ws/terminal/<UUID>. As a URL path component the UUID is exposed via:
- Reverse-proxy access logs (nginx, Caddy, Cloudflare).
- Referer headers when the page embeds external resources or error reporters.
- Browser history / bookmark sync.
- Frontend telemetry (Sentry, Bugsnag) breadcrumbs that include the WebSocket URL.
- Any shared-tenant or multi-operator log viewer.
Any authenticated user with access to one of these side channels can attach to a live session.
PoC
- Deploy nezha v2.0.9. Add at least one server. Configure two accounts:
admin(RoleAdmin, owns the server) andmember(RoleMember, no access to that server). - As
admin, open the web terminal for the server. The browser openswss://<dashboard>/ws/terminal/<UUID>. Capture this UUID from the network inspector, server access log, orRefererheader. - From a separate session logged in as
member, openwss://<dashboard>/ws/terminal/<UUID>(same UUID). The member's WebSocket attaches to the sameioStreamContextbecauseterminalStreamonly checksGetStream(streamId)— no ownership check. - The member can now read the admin's shell output and inject keystrokes, achieving shell-level RCE on the target server, with no visible signal to the legitimate session owner.
Same flow works against /ws/file/:id (file-manager hijack: arbitrary read/write on the target server's filesystem).
Impact
- Severity: Critical. Interactive RCE on a server administered by another user, with no audit signal to the rightful session owner.
- Attack complexity: Low. The attacker needs an authenticated dashboard account (which any
RoleMemberis) and one captured UUID from a side channel. - Confidentiality / Integrity / Availability: all High.
/ws/file/:idexposes arbitrary read+write on the target filesystem;/ws/terminal/:idis a full shell.
This is the same impact tier as CVE-2026-46716 (cross-tenant cron RCE) and arguably worse, because the entry point is a passively-leaked URL rather than an authenticated POST — attackers do not need direct dashboard interaction once the UUID is leaked through logs or telemetry.
Fix reference
Already fixed in master by commit 6661d6a ("fix(rpc): bind io_stream sessions to creator to prevent terminal/fm hijack"):
CreateStreamnow accepts acreatorUserID uint64and stores it on theioStreamContext.- New
IsStreamAuthorizedForUser(streamId, userID, isAdmin)helper. terminalStreamandfmStreamcall this helper before the WebSocket upgrade and before thedefer CloseStream(streamId), so a rejected attempt does not tear down a legitimate stream.
Shipped in v2.0.10 (2026-05-19). The v1.14 line has not received a backport.
Why this advisory
The fix landed silently. The other May 17–21 fixes received public GHSAs (GHSA-99gv-2m7h-3hh9, GHSA-rxf6-wjh4-jfj6, GHSA-hvv7-hfrh-7gxj, GHSA-w4g9-mxgg-j532, GHSA-6x26-5727-rrm9, GHSA-4g6j-g789-rghm) covering cron RCE, AlertRule trigger, telemetry leak, notification SSRF, DDNS SSRF, and agent forge-results respectively — but none cover the terminal / file-manager session hijack. This advisory closes that gap so operators of v1.14.x and v2.0.0–v2.0.9 know to upgrade.
Recommended action
- Publish this GHSA so v2.x operators below v2.0.10 see the alert in their dependency scanners.
- Either backport
6661d6ato a v1.14.15 release, or mark the v1.14 line end-of-life inSECURITY.mdso operators understand the support boundary.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/nezhahq/nezha"
},
"ranges": [
{
"events": [
{
"introduced": "1.14.13"
},
{
"last_affected": "1.14.14"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.0.9"
},
"package": {
"ecosystem": "Go",
"name": "github.com/nezhahq/nezha"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.0.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-26T22:31:41Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "### Summary\n\nIn nezha **v1.14.13\u2013v1.14.14** and **v2.0.0\u2013v2.0.9**, the WebSocket endpoints `GET /ws/terminal/:id` and `GET /ws/file/:id` authenticate the caller only by the presence of a valid stream UUID, with no ownership check tying that UUID to the user who created the stream. Any authenticated dashboard user (including a `RoleMember`) who learns a live stream UUID can attach to the session and gain interactive shell access or full file-manager control on the target server \u2014 i.e. cross-tenant RCE.\n\nThis was silently fixed in commit [`6661d6a`](https://github.com/nezhahq/nezha/commit/6661d6a7fc1c269f55c7f4e775082ad23fbe0f54) (2026-05-18, shipped in v2.0.10). At submission time no public CVE/GHSA covers this fix, so operators of v1.14.x and pre-v2.0.10 v2.x deployments have no signal that they are running vulnerable code.\n\n### Details\n\n**Stream allocation \u2014 `service/rpc/io_stream.go` (v2.0.9):**\n\n```go\nfunc (s *NezhaHandler) CreateStream(streamId string) {\n s.ioStreamMutex.Lock()\n defer s.ioStreamMutex.Unlock()\n\n s.ioStreams[streamId] = \u0026ioStreamContext{\n userIoConnectCh: make(chan struct{}),\n agentIoConnectCh: make(chan struct{}),\n }\n}\n```\n\nNo creator is bound to the stream.\n\n**Stream attach \u2014 `cmd/dashboard/controller/terminal.go` (v2.0.9):**\n\n```go\n// @Router /ws/terminal/{id} [get]\nfunc terminalStream(c *gin.Context) (any, error) {\n streamId := c.Param(\"id\")\n if _, err := rpc.NezhaHandlerSingleton.GetStream(streamId); err != nil {\n return nil, err\n }\n defer rpc.NezhaHandlerSingleton.CloseStream(streamId)\n // ... WebSocket upgrade and bidirectional pipe ...\n}\n```\n\nThe only authorization check is `GetStream(streamId)` \u2014 \"does this UUID exist in the in-memory map\". `getUid(c)` is never compared against the user who called `createTerminal`. The same pattern is present in `fmStream(c)` in `cmd/dashboard/controller/fm.go`.\n\n**Where the UUID leaks:**\n\n`createTerminal` returns the UUID to the legitimate client, which then opens `wss://\u003cdashboard\u003e/ws/terminal/\u003cUUID\u003e`. As a URL path component the UUID is exposed via:\n\n- Reverse-proxy access logs (nginx, Caddy, Cloudflare).\n- Referer headers when the page embeds external resources or error reporters.\n- Browser history / bookmark sync.\n- Frontend telemetry (Sentry, Bugsnag) breadcrumbs that include the WebSocket URL.\n- Any shared-tenant or multi-operator log viewer.\n\nAny authenticated user with access to one of these side channels can attach to a live session.\n\n### PoC\n\n1. Deploy nezha v2.0.9. Add at least one server. Configure two accounts: `admin` (RoleAdmin, owns the server) and `member` (RoleMember, no access to that server).\n2. As `admin`, open the web terminal for the server. The browser opens `wss://\u003cdashboard\u003e/ws/terminal/\u003cUUID\u003e`. Capture this UUID from the network inspector, server access log, or `Referer` header.\n3. From a separate session logged in as `member`, open `wss://\u003cdashboard\u003e/ws/terminal/\u003cUUID\u003e` (same UUID). The member\u0027s WebSocket attaches to the same `ioStreamContext` because `terminalStream` only checks `GetStream(streamId)` \u2014 no ownership check.\n4. The member can now read the admin\u0027s shell output and inject keystrokes, achieving shell-level RCE on the target server, with no visible signal to the legitimate session owner.\n\nSame flow works against `/ws/file/:id` (file-manager hijack: arbitrary read/write on the target server\u0027s filesystem).\n\n### Impact\n\n- **Severity**: Critical. Interactive RCE on a server administered by another user, with no audit signal to the rightful session owner.\n- **Attack complexity**: Low. The attacker needs an authenticated dashboard account (which any `RoleMember` is) and one captured UUID from a side channel.\n- **Confidentiality / Integrity / Availability**: all High. `/ws/file/:id` exposes arbitrary read+write on the target filesystem; `/ws/terminal/:id` is a full shell.\n\nThis is the same impact tier as CVE-2026-46716 (cross-tenant cron RCE) and arguably worse, because the entry point is a passively-leaked URL rather than an authenticated POST \u2014 attackers do not need direct dashboard interaction once the UUID is leaked through logs or telemetry.\n\n### Fix reference\n\nAlready fixed in master by commit [`6661d6a`](https://github.com/nezhahq/nezha/commit/6661d6a7fc1c269f55c7f4e775082ad23fbe0f54) (\"fix(rpc): bind io_stream sessions to creator to prevent terminal/fm hijack\"):\n\n- `CreateStream` now accepts a `creatorUserID uint64` and stores it on the `ioStreamContext`.\n- New `IsStreamAuthorizedForUser(streamId, userID, isAdmin)` helper.\n- `terminalStream` and `fmStream` call this helper **before** the WebSocket upgrade and **before** the `defer CloseStream(streamId)`, so a rejected attempt does not tear down a legitimate stream.\n\nShipped in v2.0.10 (2026-05-19). The v1.14 line has not received a backport.\n\n### Why this advisory\n\nThe fix landed silently. The other May 17\u201321 fixes received public GHSAs (GHSA-99gv-2m7h-3hh9, GHSA-rxf6-wjh4-jfj6, GHSA-hvv7-hfrh-7gxj, GHSA-w4g9-mxgg-j532, GHSA-6x26-5727-rrm9, GHSA-4g6j-g789-rghm) covering cron RCE, AlertRule trigger, telemetry leak, notification SSRF, DDNS SSRF, and agent forge-results respectively \u2014 but none cover the terminal / file-manager session hijack. This advisory closes that gap so operators of v1.14.x and v2.0.0\u2013v2.0.9 know to upgrade.\n\n### Recommended action\n\n- Publish this GHSA so v2.x operators below v2.0.10 see the alert in their dependency scanners.\n- Either backport `6661d6a` to a v1.14.15 release, or mark the v1.14 line end-of-life in `SECURITY.md` so operators understand the support boundary.",
"id": "GHSA-q6xx-5vr8-p898",
"modified": "2026-06-26T22:31:41Z",
"published": "2026-06-26T22:31:41Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nezhahq/nezha/security/advisories/GHSA-q6xx-5vr8-p898"
},
{
"type": "PACKAGE",
"url": "https://github.com/nezhahq/nezha"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Nezha vulnerable to cross-tenant terminal/file-manager session hijack via WebSocket stream UUID without ownership check"
}
GHSA-Q732-W4GJ-98JR
Vulnerability from github – Published: 2022-05-13 01:43 – Updated: 2022-05-13 01:43In Kanboard before 1.0.47, by altering form data, an authenticated user can add a new task to a private project of another user.
{
"affected": [],
"aliases": [
"CVE-2017-15200"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2017-10-11T01:32:00Z",
"severity": "MODERATE"
},
"details": "In Kanboard before 1.0.47, by altering form data, an authenticated user can add a new task to a private project of another user.",
"id": "GHSA-q732-w4gj-98jr",
"modified": "2022-05-13T01:43:39Z",
"published": "2022-05-13T01:43:39Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2017-15200"
},
{
"type": "WEB",
"url": "https://github.com/kanboard/kanboard/commit/074f6c104f3e49401ef0065540338fc2d4be79f0"
},
{
"type": "WEB",
"url": "https://github.com/kanboard/kanboard/commit/3e0f14ae2b0b5a44bd038a472f17eac75f538524"
},
{
"type": "WEB",
"url": "https://kanboard.net/news/version-1.0.47"
},
{
"type": "WEB",
"url": "http://openwall.com/lists/oss-security/2017/10/04/9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-Q7GM-8832-99RJ
Vulnerability from github – Published: 2026-01-26 21:30 – Updated: 2026-03-12 00:31An IDOR vulnerability exists in Omada Controllers that allows an attacker with Administrator permissions to manipulate requests and potentially hijack the Owner account.
{
"affected": [],
"aliases": [
"CVE-2025-9520"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-01-26T20:16:08Z",
"severity": "HIGH"
},
"details": "An IDOR vulnerability exists in Omada Controllers that allows an attacker with Administrator permissions to manipulate requests and potentially hijack the Owner account.",
"id": "GHSA-q7gm-8832-99rj",
"modified": "2026-03-12T00:31:15Z",
"published": "2026-01-26T21:30:36Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-9520"
},
{
"type": "WEB",
"url": "https://support.omadanetworks.com/us/document/115200"
},
{
"type": "WEB",
"url": "https://support.omadanetworks.com/us/download/software/omada-controller"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:H/VA:N/SC:L/SI:H/SA:L/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-Q7V4-X6V3-759C
Vulnerability from github – Published: 2023-06-30 03:30 – Updated: 2024-04-04 05:18The SP Project & Document Manager plugin for WordPress is vulnerable to Insecure Direct Object References in versions up to, and including, 4.67. This is due to the plugin providing user-controlled access to objects, letting a user bypass authorization and access system resources. This makes it possible for authenticated attackers with subscriber privileges or above, to change user passwords and potentially take over administrator accounts.
{
"affected": [],
"aliases": [
"CVE-2023-3063"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-06-30T02:15:09Z",
"severity": "HIGH"
},
"details": "The SP Project \u0026 Document Manager plugin for WordPress is vulnerable to Insecure Direct Object References in versions up to, and including, 4.67. This is due to the plugin providing user-controlled access to objects, letting a user bypass authorization and access system resources. This makes it possible for authenticated attackers with subscriber privileges or above, to change user passwords and potentially take over administrator accounts.",
"id": "GHSA-q7v4-x6v3-759c",
"modified": "2024-04-04T05:18:30Z",
"published": "2023-06-30T03:30:18Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-3063"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/sp-client-document-manager/trunk/classes/ajax.php#L149"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/6dc2e720-85d9-42d9-94ef-eb172425993d?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-Q83V-HQ3J-4PQ3
Vulnerability from github – Published: 2024-08-15 06:32 – Updated: 2025-03-20 18:34Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-3fff-gqw3-vj86. This link is maintained to preserve external references.
Original Description
Directus v10.13.0 allows an authenticated external attacker to modify presets created by the same user to assign them to another user. This is possible because the application only validates the user parameter in the 'POST /presets' request but not in the PATCH request. When chained with CVE-2024-6533, it could result in account takeover.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "directus"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "10.13.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": true,
"github_reviewed_at": "2024-08-15T21:56:16Z",
"nvd_published_at": "2024-08-15T04:15:07Z",
"severity": "MODERATE"
},
"details": "## Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-3fff-gqw3-vj86. This link is maintained to preserve external references.\n\n## Original Description\nDirectus v10.13.0 allows an authenticated external attacker to modify presets created by the same user to assign them to another user. This is possible because the application only validates the user parameter in the \u0027POST /presets\u0027\u00a0request but not in the PATCH request. When chained with CVE-2024-6533, it could result in account takeover.",
"id": "GHSA-q83v-hq3j-4pq3",
"modified": "2025-03-20T18:34:46Z",
"published": "2024-08-15T06:32:22Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-6534"
},
{
"type": "WEB",
"url": "https://directus.io"
},
{
"type": "WEB",
"url": "https://fluidattacks.com/advisories/capaldi"
},
{
"type": "PACKAGE",
"url": "https://github.com/directus/directus"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:N/I:L/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Duplicate Advisory: Improper access control in Directus",
"withdrawn": "2025-03-20T18:34:46Z"
}
GHSA-Q88P-27GR-Q4G5
Vulnerability from github – Published: 2026-05-14 12:30 – Updated: 2026-05-14 12:30Authorization bypass through User-Controlled key vulnerability in Akilli Commerce Software Technologies Ltd. Co. E-Commerce Website allows Session Hijacking.
This issue affects E-Commerce Website: before 4.5.001.
{
"affected": [],
"aliases": [
"CVE-2026-2347"
],
"database_specific": {
"cwe_ids": [
"CWE-639"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-05-14T10:16:19Z",
"severity": "CRITICAL"
},
"details": "Authorization bypass through User-Controlled key vulnerability in Akilli Commerce Software Technologies Ltd. Co. E-Commerce Website allows Session Hijacking.\n\nThis issue affects E-Commerce Website: before 4.5.001.",
"id": "GHSA-q88p-27gr-q4g5",
"modified": "2026-05-14T12:30:27Z",
"published": "2026-05-14T12:30:27Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2347"
},
{
"type": "WEB",
"url": "https://siberguvenlik.gov.tr/guvenlik-bildirimleri/detay/tr-26-0222"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-Q8CH-JX67-Q52X
Vulnerability from github – Published: 2026-05-21 15:34 – Updated: 2026-06-23 21:50(Externally Controlled Reference to a Resource in Another Sphere), (Authorization Bypass Through User-Controlled Key) vulnerability in Apache Camel K. Authorized users in a Kubernetes namespace can create a Build resource, controlling the Pod generation in a namespace of their choice, including the operator namespace.
This issue affects Apache Camel K: from 2.0.0 before 2.8.1, from 2.9.0 before 2.9.2, from 2.10.0 before 2.10.1.
Users are recommended to upgrade to version 2.10.1 (or 2.8.1 or 2.9.2), which fixes the issue.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/apache/camel-k/v2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.8.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/apache/camel-k/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.9.0"
},
{
"fixed": "2.9.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Go",
"name": "github.com/apache/camel-k/v2"
},
"ranges": [
{
"events": [
{
"introduced": "2.10.0"
},
{
"fixed": "2.10.1"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"2.10.0"
]
}
],
"aliases": [
"CVE-2026-45760"
],
"database_specific": {
"cwe_ids": [
"CWE-610",
"CWE-639"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-23T21:50:20Z",
"nvd_published_at": "2026-05-21T13:16:19Z",
"severity": "HIGH"
},
"details": "(Externally Controlled Reference to a Resource in Another Sphere), (Authorization Bypass Through User-Controlled Key) vulnerability in Apache Camel K. Authorized users in a Kubernetes namespace can create a Build resource, controlling the Pod generation in a namespace of their choice, including the operator namespace.\n\nThis issue affects Apache Camel K: from 2.0.0 before 2.8.1, from 2.9.0 before 2.9.2, from 2.10.0 before 2.10.1.\n\nUsers are recommended to upgrade to version 2.10.1 (or 2.8.1 or 2.9.2), which fixes the issue.",
"id": "GHSA-q8ch-jx67-q52x",
"modified": "2026-06-23T21:50:20Z",
"published": "2026-05-21T15:34:09Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45760"
},
{
"type": "WEB",
"url": "https://github.com/apache/camel-k/pull/6626"
},
{
"type": "WEB",
"url": "https://github.com/apache/camel-k/pull/6627"
},
{
"type": "WEB",
"url": "https://github.com/apache/camel-k/pull/6629"
},
{
"type": "WEB",
"url": "https://github.com/apache/camel-k/commit/1271df076f3123f5e4ec58e066e284236b1a8fb5"
},
{
"type": "WEB",
"url": "https://github.com/apache/camel-k/commit/1efa3982f4dbce0ae1f896f4003a16cae6d81ba2"
},
{
"type": "WEB",
"url": "https://github.com/apache/camel-k/commit/35dd387f58464608ab4764f67bde786cf09bc39d"
},
{
"type": "WEB",
"url": "https://camel.apache.org/security/CVE-2026-45760.html"
},
{
"type": "PACKAGE",
"url": "https://github.com/apache/camel-k"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2026/05/21/8"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Apache Camel K: Kubernetes namespace authorized users can create a Build resource"
}
Mitigation
For each and every data access, ensure that the user has sufficient privilege to access the record that is being requested.
Mitigation
Make sure that the key that is used in the lookup of a specific user's record is not controllable externally by the user or that any tampering can be detected.
Mitigation
Use encryption in order to make it more difficult to guess other legitimate values of the key or associate a digital signature with the key so that the server can verify that there has been no tampering.
No CAPEC attack patterns related to this CWE.