{"id":"CVE-2026-59155","revision":null,"records":[{"revision":"fe24c5158490477ab67920237a8f5211","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-59155","aliases":[],"title":"Nezha Monitoring: DDNS and Notification credential exposure via unredacted list API","description":"Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Prior to 2.2.5, the GET /api/v1/ddns and GET /api/v1/notification endpoints return full resource objects including plaintext third-party API credentials, including Cloudflare API tokens, TencentCloud SecretKeys, Slack, Discord, and Telegram webhook URLs with embedded bot tokens, and Authorization header values, without any field-level redaction. Any authenticated admin or PAT with nezha:ddns:read or nezha:notification:read scope can receive stored credentials through the listDDNS and listNotification handlers in a single API response. This issue is fixed in version 2.2.5.","state":0,"publishedAt":"2026-07-10T21:31:34.313+00:00","modifiedAt":"2026-07-13T17:56:44.683+00:00","affected":[{"ecosystem":"Vendor product","name":"nezha","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"nezhahq\",\n                    \"product\": \"nezha\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 2.2.5\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N","score":6.9,"severity":"MEDIUM"}],"references":["https://github.com/nezhahq/nezha/security/advisories/GHSA-ww5p-j6cj-6mqq","https://github.com/nezhahq/nezha/commit/39d398066d8c644fe452f74704e34ada6c7ab61e","https://github.com/nezhahq/nezha/releases/tag/v2.2.5"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-59155","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-59155","identifiers":["CVE-2026-59155"]},"retained":false,"historicalAffected":[]},{"revision":"0d3197ca27f842ba930f92ac82c932fc","observedAt":"2026-11-07T13:24:39.865+00:00","statement":{"source":"euvd","id":"EUVD-2026-43108","aliases":["CVE-2026-59155"],"title":"Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Prior to 2.2.5, the GET /api/v1/ddns and GET /api/v1/notification endpoints return full resource objects including plaintext third-party API cre…","description":"Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Prior to 2.2.5, the GET /api/v1/ddns and GET /api/v1/notification endpoints return full resource objects including plaintext third-party API credentials, including Cloudflare API tokens, TencentCloud SecretKeys, Slack, Discord, and Telegram webhook URLs with embedded bot tokens, and Authorization header values, without any field-level redaction. Any authenticated admin or PAT with nezha:ddns:read or nezha:notification:read scope can receive stored credentials through the listDDNS and listNotification handlers in a single API response. This issue is fixed in version 2.2.5.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N","score":6.9,"severity":null}],"references":["https://github.com/nezhahq/nezha/security/advisories/GHSA-ww5p-j6cj-6mqq","https://github.com/nezhahq/nezha/commit/39d398066d8c644fe452f74704e34ada6c7ab61e","https://github.com/nezhahq/nezha/releases/tag/v2.2.5"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-43108","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Jul 10, 2026, 9:31:34 PM","dateUpdated":"Jul 13, 2026, 5:56:44 PM"},"relatedAdvisories":[],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-43108","identifiers":["EUVD-2026-43108","CVE-2026-59155"]},"retained":false,"historicalAffected":[]},{"revision":"7427124166924840b05e891678c91a93","observedAt":"2026-10-27T15:15:28.354+00:00","statement":{"source":"nvd","id":"CVE-2026-59155","aliases":[],"title":"Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Prior to 2.2.5, the GET /api/v1/ddns and GET /api/v1/notification endpoints return full resource objects including plaintext third-party API cre…","description":"Nezha Monitoring is a self-hostable, lightweight, servers and websites monitoring and O&M tool. Prior to 2.2.5, the GET /api/v1/ddns and GET /api/v1/notification endpoints return full resource objects including plaintext third-party API credentials, including Cloudflare API tokens, TencentCloud SecretKeys, Slack, Discord, and Telegram webhook URLs with embedded bot tokens, and Authorization header values, without any field-level redaction. Any authenticated admin or PAT with nezha:ddns:read or nezha:notification:read scope can receive stored credentials through the listDDNS and listNotification handlers in a single API response. This issue is fixed in version 2.2.5.","state":0,"publishedAt":"2026-07-10T22:16:45.487+00:00","modifiedAt":"2026-10-25T15:10:00.147+00:00","affected":[],"metrics":[{"system":"CVSS 4.0 · security-advisories@github.com · Secondary","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/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","score":6.9,"severity":"MEDIUM"}],"references":["https://github.com/nezhahq/nezha/commit/39d398066d8c644fe452f74704e34ada6c7ab61e","https://github.com/nezhahq/nezha/releases/tag/v2.2.5","https://github.com/nezhahq/nezha/security/advisories/GHSA-ww5p-j6cj-6mqq"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-59155","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-200"],"productCriteria":[],"sourceDates":{"published":"2026-07-10T22:16:45.487","lastModified":"2026-10-25T15:10:00.147"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-59155","identifiers":["CVE-2026-59155"]},"retained":false,"historicalAffected":[]},{"revision":"61bba26c0f7248c9a706f0dba9719c63","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-ww5p-j6cj-6mqq","aliases":["CVE-2026-59155","GO-2026-5832"],"title":"Nezha Dashboard: DDNS and Notification credential exposure via unredacted list API","description":"### Summary\n\nThe `GET /api/v1/ddns` and `GET /api/v1/notification` endpoints return full resource objects including plaintext third-party API credentials — Cloudflare API tokens, TencentCloud SecretKeys, Slack/Discord/Telegram webhook URLs with embedded bot tokens, and Authorization header values — without any field-level redaction. Any authenticated admin who calls these endpoints receives every stored credential in the system in a single API response. A compromised admin session or leaked PAT with `nezha:ddns:read` or `nezha:notification:read` scope exposes all third-party integration secrets.\n\n### Details\n\nThe `listDDNS` and `listNotification` handlers follow an identical pattern: they call the corresponding singleton `GetSortedList()`, `copier.Copy` the full in-memory structs into a response slice, and return them via `listHandler` with zero field stripping.\n\n**DDNS — `cmd/dashboard/controller/ddns.go:25–33`:**\n\n```go\nfunc listDDNS(c *gin.Context) ([]*model.DDNSProfile, error) {\n    var ddnsProfiles []*model.DDNSProfile\n    list := singleton.DDNSShared.GetSortedList()\n    if err := copier.Copy(&ddnsProfiles, &list); err != nil {\n        return nil, err\n    }\n    return ddnsProfiles, nil\n}\n```\n\nThe `DDNSProfile` struct (`model/ddns.go:20–36`) serializes `AccessSecret` with `json:\"access_secret,omitempty\"` — non-empty Cloudflare tokens and TencentCloud SecretKeys are returned in cleartext. The `WebhookURL` and `WebhookHeaders` fields may also contain embedded secrets.\n\n**Notification — `cmd/dashboard/controller/notification.go:25–33`:**\n\n```go\nfunc listNotification(c *gin.Context) ([]*model.Notification, error) {\n    slist := singleton.NotificationShared.GetSortedList()\n    var notifications []*model.Notification\n    if err := copier.Copy(&notifications, &slist); err != nil {\n        return nil, err\n    }\n    return notifications, nil\n}\n```\n\nThe `Notification` struct (`model/notification.go:34–44`) serializes `URL`, `RequestHeader`, and `RequestBody` — all of which commonly contain embedded bot tokens (Slack, Discord, Telegram), API keys in Authorization headers, and webhook secrets.\n\n**Route and authorization (`cmd/dashboard/controller/controller.go:155, 171`):**\n\n```go\nauth.GET(\"/notification\", restScopeMiddleware(model.ScopeNotificationRead), listHandler(listNotification))\nauth.GET(\"/ddns\", restScopeMiddleware(model.ScopeDDNSRead), listHandler(listDDNS))\n```\n\nBoth routes are behind `authMw` (JWT or PAT) and the corresponding read scope. The `listHandler` → `filter` chain uses `HasPermission` (`model/common.go:63–82`) which grants admins access to ALL profiles and restricts members to their own. No separate response struct or field masking exists anywhere in the codebase — confirmed by exhaustive search for `DDNSResponse`, `DDNSView`, `NotificationResponse`, `NotificationView`, or any JSON middleware that strips sensitive fields.\n\nThe codebase already demonstrates awareness of this pattern: `serverConfigSensitiveScope()` in `cmd/dashboard/controller/api_token_scope.go:117` was introduced to restrict `client_secret` exposure via `GET /server/config/:id`, tightening the scope from `ScopeServerRead` to `ScopeServerWrite`. No equivalent protection exists for the DDNS or Notification list endpoints.\n\n**Tested at commit `3d74cd94` (master, post v2.2.3).** The vulnerable pattern has existed since the DDNS and notification list endpoints were introduced.\n\n### PoC\n\n1. Deploy nezha with at least one admin user. Configure a DDNS profile with a Cloudflare API token (AccessSecret) and a Notification webhook pointing to a Slack incoming webhook URL (`https://hooks.slack.com/services/T.../B.../xxx...`).\n\n2. Authenticate as the admin user. Call:\n\n   ```bash\n   # DDNS credentials exposed\n   curl -s -H \"Authorization: Bearer <admin_jwt>\" \\\n     https://dashboard.example.com/api/v1/ddns \\\n     | jq '.data[].access_secret'\n\n   # Notification webhook secrets exposed\n   curl -s -H \"Authorization: Bearer <admin_jwt>\" \\\n     https://dashboard.example.com/api/v1/notification \\\n     | jq '.data[].url'\n   ```\n\n3. Observe the full Cloudflare API token, Slack webhook URL with embedded token, and any `RequestHeader` values (e.g., `Authorization: Bearer ...`) returned in cleartext.\n\n4. Alternatively, create a PAT with `nezha:ddns:read` scope:\n\n   ```bash\n   curl -s -H \"Authorization: Bearer nzp_<pat_secret>\" \\\n     https://dashboard.example.com/api/v1/ddns \\\n     | jq '.data[].access_secret'\n   ```\n\n   If the PAT creator is an admin, all DDNS secrets are returned in a single response.\n\n5. **Negative control:** A member (non-admin) calling the same endpoints only sees their own profiles due to the `HasPermission` filter (`model/common.go:63–82`). However, an admin sees ALL profiles with ALL secrets. The security boundary crossed is the credential confidentiality boundary — a read-only listing endpoint should not return write-capable credentials.\n\n### Impact\n\nAn attacker who compromises an admin session or obtains a PAT with the appropriate read scope can exfiltrate all third-party API credentials stored in the dashboard — Cloudflare API tokens, TencentCloud SecretKeys, Slack/Discord/Telegram bot tokens, and any secrets embedded in webhook URLs or Authorization headers. These credentials can then be used to:\n\n- Modify DNS records for any domain managed via Cloudflare/TencentCloud DDNS profiles\n- Send messages as the Slack/Discord/Telegram bot to any configured channel\n- Access any other API the compromised credentials grant access to\n\nThe attack requires high privileges (admin JWT or PAT with appropriate scope), but the impact is amplified because a single API call exposes ALL stored credentials across ALL DDNS profiles and ALL notification webhooks, with no field-level access control separating metadata from secrets.\n\n**Suggested remediation:** Introduce separate response structs (e.g., `DDNSProfileResponse`, `NotificationResponse`) that omit sensitive fields (`AccessSecret`, `WebhookHeaders`, `URL`, `RequestHeader`) from list/read endpoints, or use `json:\"-\"` tags on sensitive fields and provide them only through a dedicated credential-retrieval endpoint with stricter authorization (analogous to the existing `serverConfigSensitiveScope()` pattern).","state":0,"publishedAt":"2026-06-26T23:55:26+00:00","modifiedAt":"2026-07-12T04:11:12.3539704+00:00","affected":[{"ecosystem":"Go","name":"github.com/nezhahq/nezha","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"2.2.5"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V4","vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:P","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"MODERATE"}],"references":["https://github.com/nezhahq/nezha/security/advisories/GHSA-ww5p-j6cj-6mqq","https://github.com/nezhahq/nezha"],"sourceUrl":"https://github.com/advisories/GHSA-ww5p-j6cj-6mqq","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-ww5p-j6cj-6mqq","identifiers":["GHSA-ww5p-j6cj-6mqq","CVE-2026-59155","GO-2026-5832"]},"retained":false,"historicalAffected":[]},{"revision":"c91ec79e8d7d402488280e15c7cacc13","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GO-2026-5832","aliases":["CVE-2026-59155","GHSA-ww5p-j6cj-6mqq"],"title":"Nezha Dashboard: DDNS and Notification credential exposure via unredacted list API in github.com/nezhahq/nezha","description":"Nezha Dashboard: DDNS and Notification credential exposure via unredacted list API in github.com/nezhahq/nezha.\n\nNOTE: The source advisory for this report contains additional versions that could not be automatically mapped to standard Go module versions.\n\n(If this is causing false-positive reports from vulnerability scanners, please suggest an edit to the report.)\n\nThe additional affected modules and versions are: github.com/nezhahq/nezha before v2.2.5.","state":0,"publishedAt":"2026-07-07T15:26:32+00:00","modifiedAt":"2026-07-12T04:11:12.3539704+00:00","affected":[{"ecosystem":"Go","name":"github.com/nezhahq/nezha","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[],"references":["https://github.com/nezhahq/nezha/security/advisories/GHSA-ww5p-j6cj-6mqq"],"sourceUrl":"https://osv.dev/vulnerability/GO-2026-5832","license":"OSV · upstream source license applies","key":"osv:GO-2026-5832","identifiers":["GO-2026-5832","CVE-2026-59155","GHSA-ww5p-j6cj-6mqq"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-07T20:52:46.7845564+00:00","complete":true,"records":1769,"lastAttemptAt":"2026-11-07T20:52:46.7845564+00:00","lastSuccessAt":"2026-11-07T20:52:46.9707302+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.9707321+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-bb5c9d5a08063ef076042e33dd72a7d0ffa4c4487efdcf3106e29ba55ec2ad57-1766179264875bb4621a23ce4c6bcebec63fb794a16e35c2f5592f4ee300ee2e","complete":true,"records":420944,"lastAttemptAt":"2026-11-07T20:52:46.1142943+00:00","lastSuccessAt":"2026-11-07T20:52:46.0341312+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.1142943+00:00","snapshotPublishedAt":"2026-11-07T20:26:36+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-cbfb00168958467aaa6015d5230faa08","complete":true,"records":13633,"lastAttemptAt":"2026-11-07T21:04:54.6100336+00:00","lastSuccessAt":"2026-11-07T21:04:54.606+00:00","error":null,"lastVerifiedAt":"2026-11-07T21:04:54.606+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13685,"expectedIdentifiers":13685,"failedIdentifiers":0},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-07T20:52:46.7845564+00:00","complete":true,"records":1096,"lastAttemptAt":"2026-11-07T20:52:46.7845564+00:00","lastSuccessAt":"2026-11-07T20:52:47.1482288+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:47.1482303+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-b9464f9c589b4886928e7045b5ad1e11","complete":true,"records":13645,"lastAttemptAt":"2026-11-07T20:52:54.6850231+00:00","lastSuccessAt":"2026-11-07T20:52:54.68+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:54.68+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13685,"expectedIdentifiers":13685,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-0eb4d6dde62dffacd040ad992d4fd5a65cd7d0dc5f5f4cfa8b41967fc6f9ca5f","complete":true,"records":9914,"lastAttemptAt":"2026-11-07T20:52:46.6024506+00:00","lastSuccessAt":"2026-11-06T20:10:36.6450506+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.6024506+00:00","snapshotPublishedAt":"2026-11-06T20:02:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-fde804134ecdda0ddd5ff5c26ee1fff5a6fa659311f7ef2e51c6ad54964db0e2","complete":true,"records":1971,"lastAttemptAt":"2026-11-07T20:52:46.3552169+00:00","lastSuccessAt":"2026-11-06T19:03:17.0399903+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.3552169+00:00","snapshotPublishedAt":"2026-11-06T18:17:57+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-335633e78a15c9cde10a6025895b5617717087fb945489ae7e15d377bacf34a9","complete":true,"records":3055,"lastAttemptAt":"2026-11-07T20:52:46.7261257+00:00","lastSuccessAt":"2026-11-06T16:03:00.7615789+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.7261257+00:00","snapshotPublishedAt":"2026-11-06T16:02:48+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-40ad6183a951565ace1520a9b4d631e1d0bfb1d4bf7c5574c375032559f3ff53","complete":true,"records":231292,"lastAttemptAt":"2026-11-07T20:52:46.4923243+00:00","lastSuccessAt":"2026-11-07T10:29:00.4821259+00:00","error":null,"lastVerifiedAt":"2026-11-07T20:52:46.4923243+00:00","snapshotPublishedAt":"2026-11-07T09:32:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}