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.
5546 vulnerabilities reference this CWE, most recent first.
GHSA-VQJC-H5M3-4Q6J
Vulnerability from github – Published: 2022-02-19 00:01 – Updated: 2023-07-24 15:30MMP: All versions prior to v1.0.3, PTP C-series: Device versions prior to v2.8.6.1, and PTMP C-series and A5x: Device versions prior to v2.5.4.1 does not perform proper authorization and authentication checks on multiple API routes. An attacker may gain access to these API routes and achieve remote code execution, create a denial-of-service condition, and obtain sensitive information.
{
"affected": [],
"aliases": [
"CVE-2022-21196"
],
"database_specific": {
"cwe_ids": [
"CWE-285",
"CWE-287",
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-02-18T18:15:00Z",
"severity": "CRITICAL"
},
"details": "MMP: All versions prior to v1.0.3, PTP C-series: Device versions prior to v2.8.6.1, and PTMP C-series and A5x: Device versions prior to v2.5.4.1 does not perform proper authorization and authentication checks on multiple API routes. An attacker may gain access to these API routes and achieve remote code execution, create a denial-of-service condition, and obtain sensitive information.",
"id": "GHSA-vqjc-h5m3-4q6j",
"modified": "2023-07-24T15:30:19Z",
"published": "2022-02-19T00:01:27Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-21196"
},
{
"type": "WEB",
"url": "https://www.cisa.gov/uscert/ics/advisories/icsa-22-034-02"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-VQX2-FGX2-5WQ9
Vulnerability from github – Published: 2026-04-16 21:28 – Updated: 2026-04-27 16:08Summary
createRouteMatcher in @clerk/nextjs, @clerk/nuxt, and @clerk/astro can be bypassed by certain crafted requests, allowing them to skip middleware gating and reach downstream handlers.
Sessions are not compromised and no existing user can be impersonated - the bypass only affects the middleware-level gating decision.
Who is affected
All apps using createRouteMatcher should upgrade to the patched versions. Patches are drop-in with no API changes. The information below describes the scope of the bypass and helps you understand whether you are potentially affected, but is not a reason to delay the upgrade.
Apps relying only on middleware gating via createRouteMatcher are affected, because a crafted request can skip middleware checks and reach downstream handlers (API routes, server components, etc.). This middleware pattern permits the bypass:
// Next.js example, equivalent patterns exist in Nuxt and Astro
const isProtectedRoute = createRouteMatcher(['/admin(.*)']);
export default clerkMiddleware(async (auth, req) => {
if (isProtectedRoute(req)) {
await auth.protect();
}
});
That said, the bypass is limited to the middleware-level route-matching gate. clerkMiddleware still authenticates the request and auth() reflects the real authentication state of the caller. Auth checks performed inside your route handlers, server components, or server actions continue to work correctly and are not affected. Whether your app is affected in practice depends on whether you have those downstream checks.
External APIs that authenticate each request with a token are also unaffected on those endpoints, since token verification runs independently.
Additionally, this common middleware pattern correctly blocks the bypass at the middleware layer:
// Next.js example, equivalent patterns exist in Nuxt and Astro
const isPublicRoute = createRouteMatcher(['/docs(.*)']);
export default clerkMiddleware(async (auth, req) => {
if (!isPublicRoute(req)) {
await auth.protect();
}
});
@clerk/shared is usually not imported directly in application code, but if you import createPathMatcher from an affected @clerk/shared version, you are also affected. Run npm why @clerk/shared (or your package manager's equivalent) to check your installed version.
Recommended actions
Install the patched version for your framework (pick the one matching your current major):
@clerk/nextjs
- v7.x: fixed in 7.2.1
- v6.x: fixed in 6.39.2
- v5.x: fixed in 5.7.6
@clerk/nuxt
- v2.x: fixed in 2.2.2
- v1.x: fixed in 1.13.28
@clerk/astro
- v3.x: fixed in 3.0.15
- v2.x: fixed in 2.17.10
- v1.x: fixed in 1.5.7
@clerk/shared
- v4.x: fixed in 4.8.1
- v3.x: fixed in 3.47.4
- v2.x: fixed in 2.22.1
Workaround
If you cannot upgrade immediately, adding server-side auth checks (auth()) inside your route handlers, server components, or server actions provides defense-in-depth against this bypass.
Timeline
This issue was reported on 13 APR 2026, patched on 15 APR 2026, and publicly disclosed on 15 APR 2026.
Thanks to Christiaan Swiers for the responsible disclosure of this vulnerability.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@clerk/nextjs"
},
"ranges": [
{
"events": [
{
"introduced": "5.0.0"
},
{
"fixed": "5.7.6"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/nuxt"
},
"ranges": [
{
"events": [
{
"introduced": "1.1.0"
},
{
"fixed": "1.13.28"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/astro"
},
"ranges": [
{
"events": [
{
"introduced": "0.0.1"
},
{
"fixed": "1.5.7"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/shared"
},
"ranges": [
{
"events": [
{
"introduced": "2.20.17"
},
{
"fixed": "2.22.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/nextjs"
},
"ranges": [
{
"events": [
{
"introduced": "6.0.0-snapshot.vb87a27f"
},
{
"fixed": "6.39.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/nextjs"
},
"ranges": [
{
"events": [
{
"introduced": "7.0.0"
},
{
"fixed": "7.2.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/nuxt"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.2.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.17.9"
},
"package": {
"ecosystem": "npm",
"name": "@clerk/astro"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0-snapshot.v20241206174604"
},
{
"fixed": "2.17.10"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/astro"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.0.15"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/shared"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0-canary.v20250225091530"
},
{
"fixed": "3.47.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "@clerk/shared"
},
"ranges": [
{
"events": [
{
"introduced": "4.0.0"
},
{
"fixed": "4.8.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41248"
],
"database_specific": {
"cwe_ids": [
"CWE-436",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-16T21:28:26Z",
"nvd_published_at": "2026-04-24T21:16:18Z",
"severity": "CRITICAL"
},
"details": "## Summary\n\n`createRouteMatcher` in `@clerk/nextjs`, `@clerk/nuxt`, and `@clerk/astro` can be bypassed by certain crafted requests, allowing them to skip middleware gating and reach downstream handlers.\n\nSessions are not compromised and no existing user can be impersonated - the bypass only affects the middleware-level gating decision.\n\n## Who is affected\n\nAll apps using `createRouteMatcher` should upgrade to the patched versions. Patches are drop-in with no API changes. The information below describes the scope of the bypass and helps you understand whether you are potentially affected, but is not a reason to delay the upgrade.\n\nApps relying only on middleware gating via `createRouteMatcher` are affected, because a crafted request can skip middleware checks and reach downstream handlers (API routes, server components, etc.). This middleware pattern permits the bypass:\n\n```ts\n// Next.js example, equivalent patterns exist in Nuxt and Astro\nconst isProtectedRoute = createRouteMatcher([\u0027/admin(.*)\u0027]);\n\nexport default clerkMiddleware(async (auth, req) =\u003e {\n if (isProtectedRoute(req)) {\n await auth.protect();\n }\n});\n```\n\nThat said, the bypass is limited to the middleware-level route-matching gate. `clerkMiddleware` still authenticates the request and `auth()` reflects the real authentication state of the caller. Auth checks performed inside your route handlers, server components, or server actions continue to work correctly and are not affected. Whether your app is affected in practice depends on whether you have those downstream checks.\n\nExternal APIs that authenticate each request with a token are also unaffected on those endpoints, since token verification runs independently.\n\nAdditionally, this common middleware pattern correctly blocks the bypass at the middleware layer:\n\n```ts\n// Next.js example, equivalent patterns exist in Nuxt and Astro\nconst isPublicRoute = createRouteMatcher([\u0027/docs(.*)\u0027]);\n\nexport default clerkMiddleware(async (auth, req) =\u003e {\n if (!isPublicRoute(req)) {\n await auth.protect();\n }\n});\n```\n\n`@clerk/shared` is usually not imported directly in application code, but if you import `createPathMatcher` from an affected `@clerk/shared` version, you are also affected. Run `npm why @clerk/shared` (or your package manager\u0027s equivalent) to check your installed version.\n\n## Recommended actions\n\nInstall the patched version for your framework (pick the one matching your current major):\n\n**`@clerk/nextjs`**\n- v7.x: fixed in `7.2.1`\n- v6.x: fixed in `6.39.2`\n- v5.x: fixed in `5.7.6`\n\n**`@clerk/nuxt`**\n- v2.x: fixed in `2.2.2`\n- v1.x: fixed in `1.13.28`\n\n**`@clerk/astro`**\n- v3.x: fixed in `3.0.15`\n- v2.x: fixed in `2.17.10`\n- v1.x: fixed in `1.5.7`\n\n**`@clerk/shared`**\n- v4.x: fixed in `4.8.1`\n- v3.x: fixed in `3.47.4`\n- v2.x: fixed in `2.22.1`\n\n## Workaround\n\nIf you cannot upgrade immediately, adding server-side auth checks (`auth()`) inside your route handlers, server components, or server actions provides defense-in-depth against this bypass.\n\n## Timeline\n\nThis issue was reported on 13 APR 2026, patched on 15 APR 2026, and publicly disclosed on 15 APR 2026.\n\nThanks to [Christiaan Swiers](https://github.com/YouGina) for the responsible disclosure of this vulnerability.",
"id": "GHSA-vqx2-fgx2-5wq9",
"modified": "2026-04-27T16:08:38Z",
"published": "2026-04-16T21:28:26Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/clerk/javascript/security/advisories/GHSA-vqx2-fgx2-5wq9"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41248"
},
{
"type": "PACKAGE",
"url": "https://github.com/clerk/javascript"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Official Clerk JavaScript SDKs: Middleware-based route protection bypass"
}
GHSA-VQX8-9XXW-F2M7
Vulnerability from github – Published: 2026-03-03 19:16 – Updated: 2026-03-30 13:37Impact
Twilio webhook replay events could bypass voice-call manager dedupe because normalized event IDs were randomized per parse. A replayed event could be treated as new and trigger duplicate or stale call-state transitions.
Affected Packages / Versions
- Package:
openclaw(npm) - Vulnerable versions:
<= 2026.2.22-2 - Patched version (released):
>= 2026.2.23
Remediation
The fix preserves provider event IDs through normalization, adds bounded replay dedupe in webhook security validation, and enforces per-call turn-token checks on call-state transitions.
Fix Commit(s)
- 1d28da55a5d0ff409e34999e0961157e9db0a2ab
Release Process Note
patched_versions is pre-set to the released version (2026.2.23) This advisory now reflects released fix version 2026.2.23.2.23`.
OpenClaw thanks @jiseoung for reporting.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "openclaw"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2026.2.23"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-32053"
],
"database_specific": {
"cwe_ids": [
"CWE-294",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-03T19:16:09Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Impact\nTwilio webhook replay events could bypass voice-call manager dedupe because normalized event IDs were randomized per parse. A replayed event could be treated as new and trigger duplicate or stale call-state transitions.\n\n## Affected Packages / Versions\n- Package: `openclaw` (npm)\n- Vulnerable versions: `\u003c= 2026.2.22-2`\n- Patched version (released): `\u003e= 2026.2.23`\n\n## Remediation\nThe fix preserves provider event IDs through normalization, adds bounded replay dedupe in webhook security validation, and enforces per-call turn-token checks on call-state transitions.\n\n## Fix Commit(s)\n- 1d28da55a5d0ff409e34999e0961157e9db0a2ab\n\n## Release Process Note\n`patched_versions` is pre-set to the released version (`2026.2.23`) This advisory now reflects released fix version `2026.2.23`.2.23`.\n\nOpenClaw thanks @jiseoung for reporting.",
"id": "GHSA-vqx8-9xxw-f2m7",
"modified": "2026-03-30T13:37:03Z",
"published": "2026-03-03T19:16:09Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-vqx8-9xxw-f2m7"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32053"
},
{
"type": "WEB",
"url": "https://github.com/openclaw/openclaw/commit/1d28da55a5d0ff409e34999e0961157e9db0a2ab"
},
{
"type": "PACKAGE",
"url": "https://github.com/openclaw/openclaw"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/openclaw-twilio-webhook-replay-bypass-via-randomized-event-id-normalization"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "OpenClaw\u0027s voice-call Twilio webhook replay could bypass manager dedupe because normalized event IDs were randomized per parse"
}
GHSA-VR2X-7687-H6QV
Vulnerability from github – Published: 2023-02-28 23:25 – Updated: 2023-03-01 01:55Impact
Resource properties secured with the security option of the ApiPlatform\Metadata\ApiProperty attribute can be disclosed to unauthorized users. The problem affects most serialization formats, including raw JSON, which is enabled by default when installing API Platform. Custom serialization formats may also be impacted. Only collection endpoints are affected by the issue, item endpoints are not. The JSON-LD format is not affected by the issue.
The result of the security rule is only executed for the first item of the collection. The result of the rule is then cached and reused for the next items. This bug can leak data to unauthorized users when the rule depends on the value of a property of the item. This bug can also hide properties that should be displayed to authorized users.
Patches
This issue impacts the 2.7, 3.0 and 3.1 branches. Upgrade to v2.7.10, v3.0.12 or v3.1.3.
Workarounds
Replace the cache_key of the context array of the Serializer inside a custom normalizer that works on objects if the security option of the ApiPlatform\Metadata\ApiProperty attribute is used.
{
"affected": [
{
"package": {
"ecosystem": "Packagist",
"name": "api-platform/core"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.0.12"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "api-platform/core"
},
"ranges": [
{
"events": [
{
"introduced": "3.1.0"
},
{
"fixed": "3.1.3"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Packagist",
"name": "api-platform/core"
},
"ranges": [
{
"events": [
{
"introduced": "2.6.0"
},
{
"fixed": "2.7.10"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2023-25575"
],
"database_specific": {
"cwe_ids": [
"CWE-842",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2023-02-28T23:25:54Z",
"nvd_published_at": "2023-02-28T23:15:00Z",
"severity": "HIGH"
},
"details": "### Impact\n\nResource properties secured with the `security` option of the `ApiPlatform\\Metadata\\ApiProperty` attribute can be disclosed to unauthorized users. The problem affects most serialization formats, including raw JSON, which is enabled by default when installing API Platform. Custom serialization formats may also be impacted. Only collection endpoints are affected by the issue, item endpoints are not. The JSON-LD format is not affected by the issue.\n\nThe result of the security rule is only executed for the first item of the collection. The result of the rule is then cached and reused for the next items. This bug can leak data to unauthorized users when the rule depends on the value of a property of the item. This bug can also hide properties that should be displayed to authorized users.\n\n### Patches\n\nThis issue impacts the 2.7, 3.0 and 3.1 branches. Upgrade to v2.7.10, v3.0.12 or v3.1.3.\n\n### Workarounds\n\nReplace the `cache_key` of the context array of the Serializer inside a custom normalizer that works on objects if the security option of the `ApiPlatform\\Metadata\\ApiProperty` attribute is used.",
"id": "GHSA-vr2x-7687-h6qv",
"modified": "2023-03-01T01:55:31Z",
"published": "2023-02-28T23:25:54Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/api-platform/core/security/advisories/GHSA-vr2x-7687-h6qv"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-25575"
},
{
"type": "WEB",
"url": "https://github.com/api-platform/core/commit/5723d68369722feefeb11e42528d9580db5dd0fb"
},
{
"type": "WEB",
"url": "https://github.com/FriendsOfPHP/security-advisories/blob/master/api-platform/core/CVE-2023-25575.yaml"
},
{
"type": "PACKAGE",
"url": "https://github.com/api-platform/core"
},
{
"type": "WEB",
"url": "https://github.com/api-platform/core/releases/tag/v2.7.10"
},
{
"type": "WEB",
"url": "https://github.com/api-platform/core/releases/tag/v3.0.12"
},
{
"type": "WEB",
"url": "https://github.com/api-platform/core/releases/tag/v3.1.3"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "api-platform/core\u0027s secured properties may be accessible within collections"
}
GHSA-VR4Q-P49J-HQ95
Vulnerability from github – Published: 2023-06-12 21:30 – Updated: 2024-04-04 04:44An issue was discovered in freakchicken kafkaUI-lite 1.2.11 allows attackers on the same network to gain escalated privileges for the nodes running on it.
{
"affected": [],
"aliases": [
"CVE-2023-27716"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-06-12T21:15:22Z",
"severity": "CRITICAL"
},
"details": "An issue was discovered in freakchicken kafkaUI-lite 1.2.11 allows attackers on the same network to gain escalated privileges for the nodes running on it.",
"id": "GHSA-vr4q-p49j-hq95",
"modified": "2024-04-04T04:44:30Z",
"published": "2023-06-12T21:30:37Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-27716"
},
{
"type": "WEB",
"url": "https://github.com/G-H-Z/CVE/blob/main/CVE-2023-27716"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-VR5R-FRMJ-8FWP
Vulnerability from github – Published: 2024-09-11 15:31 – Updated: 2024-09-11 15:31An access control vulnerability was discovered in the Reports section due to a specific access restriction not being properly enforced for users with limited privileges.
If a logged-in user with reporting privileges learns how to create a specific application request, they might be able to make limited changes to the reporting configuration. This could result in a partial loss of data integrity. In Guardian/CMC instances with a reporting configuration, there could be limited Denial of Service (DoS) impacts, as the reports may not reach their intended destination, and there could also be limited information disclosure impacts. Furthermore, modifying the destination SMTP server for the reports could lead to the compromise of external credentials, as they might be sent to an unauthorized server.
{
"affected": [],
"aliases": [
"CVE-2024-4465"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-09-11T15:15:18Z",
"severity": "MODERATE"
},
"details": "An access control vulnerability was discovered in the Reports section due to a specific access restriction not being properly enforced for users with limited privileges.\n\n\n\nIf a logged-in user with reporting privileges learns how to create a specific application request, they might be able to make limited changes to the reporting configuration. This could result in a partial loss of data integrity. In Guardian/CMC instances with a reporting configuration, there could be limited Denial of Service (DoS) impacts, as the reports may not reach their intended destination, and there could also be limited information disclosure impacts. Furthermore, modifying the destination SMTP server for the reports could lead to the compromise of external credentials, as they might be sent to an unauthorized server.",
"id": "GHSA-vr5r-frmj-8fwp",
"modified": "2024-09-11T15:31:12Z",
"published": "2024-09-11T15:31:12Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-4465"
},
{
"type": "WEB",
"url": "https://security.nozominetworks.com/NN-2024:2-01"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:L/VI:L/VA:L/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-VRC4-QVRW-2552
Vulnerability from github – Published: 2022-05-24 19:19 – Updated: 2022-05-24 19:19An improper authorization vulnerability [CWE-285] in FortiClient for Windows versions 7.0.1 and below and 6.4.2 and below may allow a local unprivileged attacker to escalate their privileges to SYSTEM via the named pipe responsible for Forticlient updates.
{
"affected": [],
"aliases": [
"CVE-2021-36183"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-11-02T19:15:00Z",
"severity": "HIGH"
},
"details": "An improper authorization vulnerability [CWE-285] in FortiClient for Windows versions 7.0.1 and below and 6.4.2 and below may allow a local unprivileged attacker to escalate their privileges to SYSTEM via the named pipe responsible for Forticlient updates.",
"id": "GHSA-vrc4-qvrw-2552",
"modified": "2022-05-24T19:19:24Z",
"published": "2022-05-24T19:19:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-36183"
},
{
"type": "WEB",
"url": "https://fortiguard.com/advisory/FG-IR-20-079"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-VRFH-RJ4Q-RMHR
Vulnerability from github – Published: 2026-05-08 20:00 – Updated: 2026-06-09 11:52Read-Only Users Can Modify Collaborative Documents via Socket.IO
Affected Component
Socket.IO collaborative document editing handler:
- backend/open_webui/socket/main.py (lines 667-721, ydoc:document:update handler)
Affected Versions
Current main branch and likely all versions with collaborative note editing.
Description
The ydoc:document:update Socket.IO event handler checks whether the sender is a member of the document's Socket.IO room (line 678) but does not verify that the sender has write permission. Users with read-only access join the document room via ydoc:document:join, which only requires read permission (line 520). Once in the room, the user can emit ydoc:document:update events that modify the in-memory Yjs document state and are broadcast to all other collaborators in real time.
The document_save_handler (line 600) correctly checks write permission before persisting to the database, so the attacker cannot directly save changes. However, the tampered content is visible to all collaborators, and if any user with write access saves the document, the injected content is persisted.
# ydoc:document:update handler (line 667) — only checks room membership, not write permission
async def on_document_update(sid, data):
document_id = normalize_document_id(data.get('document_id', ''))
# ...
room = f'doc_{document_id}'
if room not in sio.rooms(sid): # Room membership check only
return
# Applies update to Yjs state and broadcasts to all users
YDOC_MANAGER.apply_update(document_id, update)
await sio.emit('ydoc:document:update', {...}, room=room, skip_sid=sid)
Compare with ydoc:document:join (line 520) which checks permission:
# Only checks READ permission — so read-only users join the room
if not has_access(user_id, type, id, 'read', db=db):
return
CVSS 3.1 Breakdown
| Metric | Value | Rationale |
|---|---|---|
| Attack Vector | Network (N) | Exploited remotely via Socket.IO events |
| Attack Complexity | Low (L) | No special conditions; attacker emits a standard Socket.IO event |
| Privileges Required | Low (L) | Requires a valid user account with read access to the shared note |
| User Interaction | None (N) | Modifications appear in real time without victim action; however, persistence requires a write-access user to save |
| Scope | Unchanged (U) | Impact is within the collaborative document context |
| Confidentiality | None (N) | No data disclosure beyond what read access already provides |
| Integrity | Low (L) | In-memory document state is modified and broadcast; persistence is indirect (requires another user to save) |
| Availability | Low (L) | Collaborative editing session can be disrupted with invalid content |
Attack Scenario
- User A creates a note and shares it with User B with read permission.
- User B opens the note, which triggers
ydoc:document:join— the server checks read permission and adds User B to the document room. - User B emits
ydoc:document:updatewith a crafted Yjs update payload via the Socket.IO connection (bypassing any frontend read-only enforcement). - The server applies the update to the Yjs document state and broadcasts it to all collaborators.
- User A sees the injected content appear in their editor in real time.
- If User A saves the document (intentionally or via autosave), the tampered content is persisted to the database — User A's save passes the write permission check since User A is the owner.
Impact
- Read-only users can inject, modify, or delete content in collaborative documents
- Modifications are broadcast in real time to all collaborators, causing confusion or disruption
- If a write-access user saves (including autosave), the tampered content is permanently persisted
- Undermines the read/write permission model for collaborative editing
Preconditions
- Attacker must have a valid user account with read access to a shared note
- The note must be open for collaborative editing (at least one other user viewing it, or the attacker can wait for a write-access user to open and save)
Consolidation
This advisory covers read-only users modifying collaborative notes over Socket.IO. Two handlers were affected, both fixed in v0.9.0:
ydoc:document:update— checked only room membership, not write permission, so a read-only collaborator could inject in-memory document updates broadcast to other collaborators (persistence indirect). @Classic298.document_save_handler— checkedpermission='read'while persisting viaNotes.update_note_by_id, so a read-only collaborator could persist note changes directly. Reported by @hacnho
One CVE for the consolidated advisory.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.8.12"
},
"package": {
"ecosystem": "PyPI",
"name": "open-webui"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.9.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-44564"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-08T20:00:57Z",
"nvd_published_at": "2026-05-15T20:16:48Z",
"severity": "MODERATE"
},
"details": "# Read-Only Users Can Modify Collaborative Documents via Socket.IO\n\n## Affected Component\n\nSocket.IO collaborative document editing handler:\n- `backend/open_webui/socket/main.py` (lines 667-721, `ydoc:document:update` handler)\n\n## Affected Versions\n\nCurrent main branch and likely all versions with collaborative note editing.\n\n## Description\n\nThe `ydoc:document:update` Socket.IO event handler checks whether the sender is a member of the document\u0027s Socket.IO room (line 678) but does not verify that the sender has **write** permission. Users with read-only access join the document room via `ydoc:document:join`, which only requires `read` permission (line 520). Once in the room, the user can emit `ydoc:document:update` events that modify the in-memory Yjs document state and are broadcast to all other collaborators in real time.\n\nThe `document_save_handler` (line 600) correctly checks `write` permission before persisting to the database, so the attacker cannot directly save changes. However, the tampered content is visible to all collaborators, and if any user with write access saves the document, the injected content is persisted.\n\n```python\n# ydoc:document:update handler (line 667) \u2014 only checks room membership, not write permission\nasync def on_document_update(sid, data):\n document_id = normalize_document_id(data.get(\u0027document_id\u0027, \u0027\u0027))\n # ...\n room = f\u0027doc_{document_id}\u0027\n if room not in sio.rooms(sid): # Room membership check only\n return\n # Applies update to Yjs state and broadcasts to all users\n YDOC_MANAGER.apply_update(document_id, update)\n await sio.emit(\u0027ydoc:document:update\u0027, {...}, room=room, skip_sid=sid)\n```\n\nCompare with `ydoc:document:join` (line 520) which checks permission:\n\n```python\n# Only checks READ permission \u2014 so read-only users join the room\nif not has_access(user_id, type, id, \u0027read\u0027, db=db):\n return\n```\n\n## CVSS 3.1 Breakdown\n\n| Metric | Value | Rationale |\n|--------|-------|-----------|\n| Attack Vector | Network (N) | Exploited remotely via Socket.IO events |\n| Attack Complexity | Low (L) | No special conditions; attacker emits a standard Socket.IO event |\n| Privileges Required | Low (L) | Requires a valid user account with read access to the shared note |\n| User Interaction | None (N) | Modifications appear in real time without victim action; however, persistence requires a write-access user to save |\n| Scope | Unchanged (U) | Impact is within the collaborative document context |\n| Confidentiality | None (N) | No data disclosure beyond what read access already provides |\n| Integrity | Low (L) | In-memory document state is modified and broadcast; persistence is indirect (requires another user to save) |\n| Availability | Low (L) | Collaborative editing session can be disrupted with invalid content |\n\n## Attack Scenario\n\n1. User A creates a note and shares it with User B with **read** permission.\n2. User B opens the note, which triggers `ydoc:document:join` \u2014 the server checks read permission and adds User B to the document room.\n3. User B emits `ydoc:document:update` with a crafted Yjs update payload via the Socket.IO connection (bypassing any frontend read-only enforcement).\n4. The server applies the update to the Yjs document state and broadcasts it to all collaborators.\n5. User A sees the injected content appear in their editor in real time.\n6. If User A saves the document (intentionally or via autosave), the tampered content is persisted to the database \u2014 User A\u0027s save passes the write permission check since User A is the owner.\n\n## Impact\n\n- Read-only users can inject, modify, or delete content in collaborative documents\n- Modifications are broadcast in real time to all collaborators, causing confusion or disruption\n- If a write-access user saves (including autosave), the tampered content is permanently persisted\n- Undermines the read/write permission model for collaborative editing\n\n## Preconditions\n\n- Attacker must have a valid user account with read access to a shared note\n- The note must be open for collaborative editing (at least one other user viewing it, or the attacker can wait for a write-access user to open and save)\n\n## Consolidation\n\nThis advisory covers read-only users modifying collaborative notes over Socket.IO. Two handlers were affected, both fixed in v0.9.0:\n\n- `ydoc:document:update` \u2014 checked only room membership, not write permission, so a read-only collaborator could inject in-memory document updates broadcast to other collaborators (persistence indirect). @Classic298.\n- `document_save_handler` \u2014 checked `permission=\u0027read\u0027` while persisting via `Notes.update_note_by_id`, so a read-only collaborator could persist note changes directly. Reported by @hacnho \n\nOne CVE for the consolidated advisory.",
"id": "GHSA-vrfh-rj4q-rmhr",
"modified": "2026-06-09T11:52:49Z",
"published": "2026-05-08T20:00:57Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/open-webui/open-webui/security/advisories/GHSA-vrfh-rj4q-rmhr"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44564"
},
{
"type": "PACKAGE",
"url": "https://github.com/open-webui/open-webui"
}
],
"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:L",
"type": "CVSS_V3"
}
],
"summary": "Read-Only Open WebUI Users Can Modify Collaborative Documents via Socket.IO"
}
GHSA-VRGC-533G-V7R4
Vulnerability from github – Published: 2022-06-07 00:00 – Updated: 2022-06-14 00:00Incorrect authorization in GitLab EE affecting all versions from 12.0 before 14.9.5, all versions starting from 14.10 before 14.10.4, all versions starting from 15.0 before 15.0.1 allowed an attacker already in possession of a valid Project Deploy Token to misuse it from any location even when IP address restrictions were configured
{
"affected": [],
"aliases": [
"CVE-2022-1936"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-06-06T17:15:00Z",
"severity": "MODERATE"
},
"details": "Incorrect authorization in GitLab EE affecting all versions from 12.0 before 14.9.5, all versions starting from 14.10 before 14.10.4, all versions starting from 15.0 before 15.0.1 allowed an attacker already in possession of a valid Project Deploy Token to misuse it from any location even when IP address restrictions were configured",
"id": "GHSA-vrgc-533g-v7r4",
"modified": "2022-06-14T00:00:28Z",
"published": "2022-06-07T00:00:35Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-1936"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/cves/-/blob/master/2022/CVE-2022-1936.json"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/gitlab/-/issues/363638"
}
],
"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-VRMH-5MMX-HJWX
Vulnerability from github – Published: 2026-06-10 13:39 – Updated: 2026-06-26 21:29Private services (EnableShowInService: false) are enumerable via per-server endpoints, leaking name and timing data
CWE: CWE-285 (Improper Authorization) via CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) and CWE-863 (Incorrect Authorization — inconsistent gating across data-reader paths)
CVSS v3.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N → 5.3 (Medium)
Summary
The EnableShowInService flag on a Service is meant to gate that service's visibility from the public dashboard. The main service-listing endpoint (GET /api/v1/service → showService) correctly filters services with EnableShowInService: false via ServiceSentinel.CopyStats() (service/singleton/servicesentinel.go:421-438). However, two adjacent reader endpoints retrieve service objects through code paths that do not honor the same flag:
GET /api/v1/server/:id/service(listServerServices) iteratesServiceSentinel.GetSortedList()(which returns every service regardless of visibility) and emits service ID, name, and timing data for any service monitoring the queried server.GET /api/v1/service/:id/history(getServiceHistory) callsServiceSentinel.Get(serviceID)directly and emits the service name (and aggregated per-server stats for servers the viewer can see).
Both endpoints are mounted on the optionalAuth group, so an unauthenticated visitor can enumerate hidden services as long as they can guess a public server ID (linear scan over a small numeric ID space) or a service ID (likewise). The service owner's intent — "hide this from the public" via EnableShowInService: false — is silently bypassed.
Affected
- nezha
masterat HEAD636f4a99e6c3d8d75f17fdf7ad55d4ee0f73f1c0(the audit checkout) - All recent 2.x releases that share this code path (post the
EnableShowInServicefilter introduction atCopyStats)
Vulnerability details
[A] — single-source-of-truth filter exists at the listing site
service/singleton/servicesentinel.go:421-438:
func (ss *ServiceSentinel) CopyStats() map[uint64]model.ServiceResponseItem {
var stats map[uint64]*serviceResponseItem
copier.Copy(&stats, ss.LoadStats())
sri := make(map[uint64]model.ServiceResponseItem)
for k, service := range stats {
if !service.service.EnableShowInService { // [A] filter here
delete(stats, k)
continue
}
service.ServiceName = service.service.Name
sri[k] = service.ServiceResponseItem
}
return sri
}
CopyStats() is the only reader that respects EnableShowInService. Get() and GetSortedList() immediately below it return the raw services with no such filter:
func (ss *ServiceSentinel) Get(id uint64) (s *model.Service, ok bool) {
ss.servicesLock.RLock(); defer ss.servicesLock.RUnlock()
s, ok = ss.services[id]
return // [A'] no EnableShowInService check
}
[B] — listServerServices iterates GetSortedList() and emits hidden services
cmd/dashboard/controller/service.go:258-340 (GET /api/v1/server/:id/service):
func listServerServices(c *gin.Context) ([]*model.ServiceInfos, error) {
// ... server existence + userCanViewServer check ...
services := singleton.ServiceSentinelShared.GetSortedList() // [B] all services, no filter
for _, service := range services {
if service.Cover == model.ServiceCoverAll {
if service.SkipServers[serverID] { continue }
} else {
if !service.SkipServers[serverID] { continue }
}
// ... fetch history ...
infos := &model.ServiceInfos{
ServiceID: service.ID,
ServerID: serverID,
ServiceName: service.Name, // [B'] leaked
ServerName: server.Name,
// ... timing data ...
}
result = append(result, infos)
}
return result, nil
}
The DB-fallback path at queryServerServicesFromDB (service.go:340-) has the same structure: iterates services (the same GetSortedList() output) and emits ServiceName for any service monitoring serverID.
[C] — getServiceHistory returns the service name for any ID
cmd/dashboard/controller/service.go:126-180 (GET /api/v1/service/:id/history):
func getServiceHistory(c *gin.Context) (*model.ServiceHistoryResponse, error) {
serviceID, _ := strconv.ParseUint(c.Param("id"), 10, 64)
service, ok := singleton.ServiceSentinelShared.Get(serviceID) // [C] no filter
if !ok || service == nil {
return nil, singleton.Localizer.ErrorT("service not found")
}
// period restriction for guests (1d only) — but the service exists,
// and ServiceName is set unconditionally:
response := &model.ServiceHistoryResponse{
ServiceID: serviceID,
ServiceName: service.Name, // [C'] leaked
Servers: make([]model.ServerServiceStats, 0),
}
// ... per-server data is filtered via userCanViewServer — that part is correct ...
return response, nil
}
The per-server data inside the response IS correctly filtered via userCanViewServer. The service NAME is not.
The mismatch
[A] (CopyStats) gates by EnableShowInService because that's the listing endpoint's contract. [A'] (Get) / GetSortedList() return the raw data because they're "internal" accessors. But [B] and [C] are public-reachable endpoints that use those raw accessors and emit identifying information about services the owner marked as private. The visibility flag exists; it just isn't enforced at every reader of the same data.
A correct guard would either:
- Move the EnableShowInService filter into Get() / GetSortedList() themselves, gated by "caller is admin or service owner"
- Re-check EnableShowInService at every endpoint that emits service identity (name/id/timing)
Proof of concept
Setup (any nezha 2.x deployment):
1. User A (member) creates a Service "Internal-CRM-Health" with EnableShowInService: false, monitoring server S which is public (HideForGuest: false).
2. The service does not appear in GET /api/v1/service (the main listing correctly hides it).
Enumeration as an unauthenticated guest:
# Find services that monitor server S
curl -s 'https://nezha.example/api/v1/server/'"$S_ID"'/service'
# →
# {"success":true,"data":[
# {"service_id":42,"server_id":1,"service_name":"Internal-CRM-Health","server_name":"web-01",
# "display_index":0,"created_at":[...],"avg_delay":[...]}
# ]}
#
# Hidden service is leaked: ID, name, and per-server timing data are all visible.
Confirmation via the second endpoint:
curl -s 'https://nezha.example/api/v1/service/42/history?period=1d'
# →
# {"success":true,"data":{
# "service_id":42,
# "service_name":"Internal-CRM-Health", ← leaked even for direct ID lookup
# "servers":[] ← per-server data correctly hidden
# }}
A scripted enumeration over public server IDs (a low-cardinality numeric space — typical nezha deployments have <1000 servers) trivially recovers the full set of hidden services that monitor any public server, along with their names and timing patterns.
Impact
Direct
Service names in nezha deployments are frequently descriptive of the underlying business asset they monitor: "Production CRM Monitor", "Internal Wiki Health", "Backup-Vault Connectivity", "Stripe Webhook Latency". The leak therefore:
- Discloses the existence and purpose of internal services that the owner explicitly hid from the public dashboard.
- Exposes timing/latency data for the monitored relationship between a private service and any public server it touches — sufficient for a competitor or attacker to infer business activity patterns, outage windows, and probable backend topology.
- Confirms presence/absence of a service ID via the second endpoint — an oracle that lets an unauthenticated visitor enumerate the service-id namespace and learn the deployment's service count and naming convention even when no public servers exist as enumeration vectors.
Indirect / second-order
- Affects multi-tenant public dashboards: nezha is frequently deployed as a public status page with a private "internal" tier in the same dashboard. The bypass collapses the privacy boundary between these tiers.
- Composability with prior advisories: the recent fixes for
GHSA-rxf6-wjh4-jfj6(cross-user trigger-task firing),GHSA-hvv7-hfrh-7gxj(WS server-stream cross-tenant leak), andGHSA-4g6j-g789-rghm(forged monitor results) all address the cross-tenant visibility model. This finding is a sibling that closes one more reader gap in the same model.
Suggested fix
Either of:
- Centralize the filter in
ServiceSentinel— changeGet(id)andGetSortedList()to accept the*gin.Context(or a viewer context) and apply theEnableShowInServicefilter plus an admin-or-owner override. This guarantees every reader inherits the gate:
go
func (ss *ServiceSentinel) GetForViewer(c *gin.Context, id uint64) (*model.Service, bool) {
s, ok := ss.Get(id)
if !ok { return nil, false }
if !s.EnableShowInService && !callerIsAdminOrOwns(c, s) {
return nil, false
}
return s, true
}
- Recheck at every endpoint that emits service identity — add the EnableShowInService + ownership check at the top of
listServerServices,getServiceHistory, and anywhere elseGetSortedList()/Get()results flow to a response. More surgical but easier to miss next time.
Option (1) is symmetric with how userCanViewServer centralizes the server-visibility decision; the same pattern at the service layer would close this class once.
{
"affected": [
{
"package": {
"ecosystem": "Go",
"name": "github.com/nezhahq/nezha"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.0.14"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-49397"
],
"database_specific": {
"cwe_ids": [
"CWE-200",
"CWE-285",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-10T13:39:24Z",
"nvd_published_at": "2026-06-12T22:16:51Z",
"severity": "MODERATE"
},
"details": "# Private services (`EnableShowInService: false`) are enumerable via per-server endpoints, leaking name and timing data\n\n**CWE**: CWE-285 (Improper Authorization) via CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor) and CWE-863 (Incorrect Authorization \u2014 inconsistent gating across data-reader paths)\n\n**CVSS v3.1**: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N` \u2192 5.3 (Medium)\n\n## Summary\n\nThe `EnableShowInService` flag on a `Service` is meant to gate that service\u0027s visibility from the public dashboard. The main service-listing endpoint (`GET /api/v1/service` \u2192 `showService`) correctly filters services with `EnableShowInService: false` via `ServiceSentinel.CopyStats()` (`service/singleton/servicesentinel.go:421-438`). However, two adjacent reader endpoints retrieve service objects through code paths that do not honor the same flag:\n\n- `GET /api/v1/server/:id/service` (`listServerServices`) iterates `ServiceSentinel.GetSortedList()` (which returns every service regardless of visibility) and emits service ID, name, and timing data for any service monitoring the queried server.\n- `GET /api/v1/service/:id/history` (`getServiceHistory`) calls `ServiceSentinel.Get(serviceID)` directly and emits the service name (and aggregated per-server stats for servers the viewer can see).\n\nBoth endpoints are mounted on the `optionalAuth` group, so an unauthenticated visitor can enumerate hidden services as long as they can guess a public server ID (linear scan over a small numeric ID space) or a service ID (likewise). The service owner\u0027s intent \u2014 \"hide this from the public\" via `EnableShowInService: false` \u2014 is silently bypassed.\n\n## Affected\n\n- nezha `master` at HEAD `636f4a99e6c3d8d75f17fdf7ad55d4ee0f73f1c0` (the audit checkout)\n- All recent 2.x releases that share this code path (post the `EnableShowInService` filter introduction at `CopyStats`)\n\n## Vulnerability details\n\n### [A] \u2014 single-source-of-truth filter exists at the listing site\n\n`service/singleton/servicesentinel.go:421-438`:\n\n```go\nfunc (ss *ServiceSentinel) CopyStats() map[uint64]model.ServiceResponseItem {\n var stats map[uint64]*serviceResponseItem\n copier.Copy(\u0026stats, ss.LoadStats())\n\n sri := make(map[uint64]model.ServiceResponseItem)\n for k, service := range stats {\n if !service.service.EnableShowInService { // [A] filter here\n delete(stats, k)\n continue\n }\n service.ServiceName = service.service.Name\n sri[k] = service.ServiceResponseItem\n }\n return sri\n}\n```\n\n`CopyStats()` is the only reader that respects `EnableShowInService`. `Get()` and `GetSortedList()` immediately below it return the raw services with no such filter:\n\n```go\nfunc (ss *ServiceSentinel) Get(id uint64) (s *model.Service, ok bool) {\n ss.servicesLock.RLock(); defer ss.servicesLock.RUnlock()\n s, ok = ss.services[id]\n return // [A\u0027] no EnableShowInService check\n}\n```\n\n### [B] \u2014 `listServerServices` iterates `GetSortedList()` and emits hidden services\n\n`cmd/dashboard/controller/service.go:258-340` (`GET /api/v1/server/:id/service`):\n\n```go\nfunc listServerServices(c *gin.Context) ([]*model.ServiceInfos, error) {\n // ... server existence + userCanViewServer check ...\n services := singleton.ServiceSentinelShared.GetSortedList() // [B] all services, no filter\n\n for _, service := range services {\n if service.Cover == model.ServiceCoverAll {\n if service.SkipServers[serverID] { continue }\n } else {\n if !service.SkipServers[serverID] { continue }\n }\n // ... fetch history ...\n infos := \u0026model.ServiceInfos{\n ServiceID: service.ID,\n ServerID: serverID,\n ServiceName: service.Name, // [B\u0027] leaked\n ServerName: server.Name,\n // ... timing data ...\n }\n result = append(result, infos)\n }\n return result, nil\n}\n```\n\nThe DB-fallback path at `queryServerServicesFromDB` (`service.go:340-`) has the same structure: iterates `services` (the same `GetSortedList()` output) and emits ServiceName for any service monitoring `serverID`.\n\n### [C] \u2014 `getServiceHistory` returns the service name for any ID\n\n`cmd/dashboard/controller/service.go:126-180` (`GET /api/v1/service/:id/history`):\n\n```go\nfunc getServiceHistory(c *gin.Context) (*model.ServiceHistoryResponse, error) {\n serviceID, _ := strconv.ParseUint(c.Param(\"id\"), 10, 64)\n service, ok := singleton.ServiceSentinelShared.Get(serviceID) // [C] no filter\n if !ok || service == nil {\n return nil, singleton.Localizer.ErrorT(\"service not found\")\n }\n // period restriction for guests (1d only) \u2014 but the service exists,\n // and ServiceName is set unconditionally:\n response := \u0026model.ServiceHistoryResponse{\n ServiceID: serviceID,\n ServiceName: service.Name, // [C\u0027] leaked\n Servers: make([]model.ServerServiceStats, 0),\n }\n // ... per-server data is filtered via userCanViewServer \u2014 that part is correct ...\n return response, nil\n}\n```\n\nThe per-server data inside the response IS correctly filtered via `userCanViewServer`. The service NAME is not.\n\n### The mismatch\n\n[A] (`CopyStats`) gates by `EnableShowInService` because that\u0027s the listing endpoint\u0027s contract. [A\u0027] (`Get`) / `GetSortedList()` return the raw data because they\u0027re \"internal\" accessors. But [B] and [C] are public-reachable endpoints that use those raw accessors and emit identifying information about services the owner marked as private. The visibility flag exists; it just isn\u0027t enforced at every reader of the same data.\n\nA correct guard would either:\n- Move the `EnableShowInService` filter into `Get()` / `GetSortedList()` themselves, gated by \"caller is admin or service owner\"\n- Re-check `EnableShowInService` at every endpoint that emits service identity (name/id/timing)\n\n## Proof of concept\n\nSetup (any nezha 2.x deployment):\n1. User A (member) creates a Service \"Internal-CRM-Health\" with `EnableShowInService: false`, monitoring server `S` which is public (`HideForGuest: false`).\n2. The service does not appear in `GET /api/v1/service` (the main listing correctly hides it).\n\nEnumeration as an unauthenticated guest:\n\n```bash\n# Find services that monitor server S\ncurl -s \u0027https://nezha.example/api/v1/server/\u0027\"$S_ID\"\u0027/service\u0027\n# \u2192\n# {\"success\":true,\"data\":[\n# {\"service_id\":42,\"server_id\":1,\"service_name\":\"Internal-CRM-Health\",\"server_name\":\"web-01\",\n# \"display_index\":0,\"created_at\":[...],\"avg_delay\":[...]}\n# ]}\n#\n# Hidden service is leaked: ID, name, and per-server timing data are all visible.\n```\n\nConfirmation via the second endpoint:\n\n```bash\ncurl -s \u0027https://nezha.example/api/v1/service/42/history?period=1d\u0027\n# \u2192\n# {\"success\":true,\"data\":{\n# \"service_id\":42,\n# \"service_name\":\"Internal-CRM-Health\", \u2190 leaked even for direct ID lookup\n# \"servers\":[] \u2190 per-server data correctly hidden\n# }}\n```\n\nA scripted enumeration over public server IDs (a low-cardinality numeric space \u2014 typical nezha deployments have \u003c1000 servers) trivially recovers the full set of hidden services that monitor any public server, along with their names and timing patterns.\n\n## Impact\n\n### Direct\n\nService names in nezha deployments are frequently descriptive of the underlying business asset they monitor: `\"Production CRM Monitor\"`, `\"Internal Wiki Health\"`, `\"Backup-Vault Connectivity\"`, `\"Stripe Webhook Latency\"`. The leak therefore:\n\n- **Discloses the existence and purpose of internal services** that the owner explicitly hid from the public dashboard.\n- **Exposes timing/latency data** for the monitored relationship between a private service and any public server it touches \u2014 sufficient for a competitor or attacker to infer business activity patterns, outage windows, and probable backend topology.\n- **Confirms presence/absence of a service ID** via the second endpoint \u2014 an oracle that lets an unauthenticated visitor enumerate the service-id namespace and learn the deployment\u0027s service count and naming convention even when no public servers exist as enumeration vectors.\n\n### Indirect / second-order\n\n- **Affects multi-tenant public dashboards**: nezha is frequently deployed as a public status page with a private \"internal\" tier in the same dashboard. The bypass collapses the privacy boundary between these tiers.\n- **Composability with prior advisories**: the recent fixes for `GHSA-rxf6-wjh4-jfj6` (cross-user trigger-task firing), `GHSA-hvv7-hfrh-7gxj` (WS server-stream cross-tenant leak), and `GHSA-4g6j-g789-rghm` (forged monitor results) all address the cross-tenant visibility model. This finding is a sibling that closes one more reader gap in the same model.\n\n## Suggested fix\n\nEither of:\n\n1. **Centralize the filter in `ServiceSentinel`** \u2014 change `Get(id)` and `GetSortedList()` to accept the `*gin.Context` (or a viewer context) and apply the `EnableShowInService` filter plus an admin-or-owner override. This guarantees every reader inherits the gate:\n\n ```go\n func (ss *ServiceSentinel) GetForViewer(c *gin.Context, id uint64) (*model.Service, bool) {\n s, ok := ss.Get(id)\n if !ok { return nil, false }\n if !s.EnableShowInService \u0026\u0026 !callerIsAdminOrOwns(c, s) {\n return nil, false\n }\n return s, true\n }\n ```\n\n2. **Recheck at every endpoint that emits service identity** \u2014 add the EnableShowInService + ownership check at the top of `listServerServices`, `getServiceHistory`, and anywhere else `GetSortedList()`/`Get()` results flow to a response. More surgical but easier to miss next time.\n\nOption (1) is symmetric with how `userCanViewServer` centralizes the server-visibility decision; the same pattern at the service layer would close this class once.",
"id": "GHSA-vrmh-5mmx-hjwx",
"modified": "2026-06-26T21:29:08Z",
"published": "2026-06-10T13:39:24Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nezhahq/nezha/security/advisories/GHSA-vrmh-5mmx-hjwx"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-49397"
},
{
"type": "PACKAGE",
"url": "https://github.com/nezhahq/nezha"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Nezha\u0027s private services (`EnableShowInService: false`) are enumerable via per-server endpoints, leaking name and timing data"
}
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.