<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="/static/style.xsl" type="text/xsl"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title>Most recent sightings.</title>
    <link>https://vulnerability.circl.lu</link>
    <description>Contains only the most 10 recent sightings.</description>
    <docs>http://www.rssboard.org/rss-specification</docs>
    <generator>python-feedgen</generator>
    <language>en</language>
    <lastBuildDate>Tue, 11 Aug 2026 07:20:49 +0000</lastBuildDate>
    <item>
      <title>862e95b4-6bb7-417f-8e2a-c5b59e279a5d</title>
      <link>https://vulnerability.circl.lu/sighting/862e95b4-6bb7-417f-8e2a-c5b59e279a5d/export</link>
      <description>{"uuid": "862e95b4-6bb7-417f-8e2a-c5b59e279a5d", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-51584", "type": "seen", "source": "https://gist.github.com/seiyaibuki0523/33a4c06eb7d10914e5e5152ecd5100ec", "content": "# CVE-2026-51584 \u2014 SSO Account Takeover in Memos (Missing External-Identity Binding)\n\n&amp;gt; Source-level security advisory. Memos' OAuth2/SSO sign-in resolved the local\n&amp;gt; account using the IdP-supplied identifier (username) as the sole lookup key,\n&amp;gt; with no binding to the IdP's stable subject. An attacker who controls their\n&amp;gt; identifier on any configured public IdP could take over an arbitrary local\n&amp;gt; account.\n\n## Summary\n\n| Field | Value |\n|---|---|\n| CVE | `CVE-2026-51584` |\n| Vulnerability type | Incorrect Access Control \u2192 Account Takeover (CWE-287 / CWE-284) |\n| Vendor / product | usememos / memos |\n| Affected component | `server/router/api/v1/auth_service.go` (`SignIn`, ssoCredentials branch) |\n| Affected versions | \u2264 v0.27.1 |\n| Fixed version | v0.28.0 |\n| Fixing commit | [`d688914b`](https://github.com/usememos/memos/commit/d688914b2864791eeadbf21c882608632875f17c) |\n| Attack type | Remote |\n| Impact | Escalation of privileges / account takeover |\n| Discoverer | Casper Chen, Cevanex |\n\n## Severity\n\n- **Severity:** High\n- **CVSS v3.1 (suggested):** `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N` \u2192 Base 9.1 *(inferred; not yet NVD-assigned)*\n- **Source:** inferred from source-level analysis, not NVD\n\nWhere SSO is enabled against a public IdP whose mapped identifier is\nattacker-controllable (username, email, preferred_username, or name), an\nattacker can authenticate as any existing local user, including admins \u2014\na full account takeover with no prior access to the victim account.\n\n## Root Cause\n\nIn the vulnerable `SignIn` handler, the SSO branch looked up the local user\nusing only the IdP-supplied identifier as the key:\n\n```go\n// server/router/api/v1/auth_service.go (v0.27.x, ssoCredentials branch)\nuser, err := s.Store.GetUser(ctx, &amp;amp;store.FindUser{\n    Username: &amp;amp;userInfo.Identifier,   // &amp;lt;-- only lookup key\n})\nif err != nil { /* ... */ }\nif user == nil {\n    // ... create new user with Username: userInfo.Identifier\n}\nexistingUser = user\n// existingUser is then passed to doSignIn(), which signs a JWT containing\n// existingUser.ID, existingUser.Username, existingUser.Role.\n```\n\nThere was **no** `user_identity` table or equivalent `(user_id, idp_id,\nexternal_sub)` binding. The IdP's stable `sub` claim was discarded \u2014\n`oauth2.IdentityProvider.UserInfo` populated only `Identifier` / `DisplayName`\n/ `Email` / `AvatarURL` from the configured `field_mapping`. By default and in\nevery documented example, `field_mapping.identifier` is `username`, `email`,\n`preferred_username`, or `name` \u2014 all attacker-controllable on any major public\nIdP.\n\nConsequently, an attacker who sets their identifier on the IdP to match a\nvictim's Memos username causes the lookup to resolve to the victim's local\naccount, and `doSignIn()` mints a valid session (JWT) for that account.\n\n## Proof of Concept\n\nPrerequisites: a Memos instance with OAuth2 SSO enabled against a public IdP,\nusing a default `field_mapping.identifier` (e.g. `email` or\n`preferred_username`), and knowledge of a victim's Memos username.\n\n1. On the configured IdP, set the account's mapped identifier field to the\n   victim's Memos username / email.\n2. Complete the standard OAuth2 authorization-code flow into Memos.\n3. During `SignIn`, `GetUser(FindUser{Username: &amp;amp;userInfo.Identifier})` resolves\n   to the **victim's** existing local user.\n4. `doSignIn()` issues an access token bound to the victim's ID / username /\n   role. The attacker now holds a valid session for the victim account.\n\n## The Fix\n\nFixed in **v0.28.0** by commit\n[`d688914b`](https://github.com/usememos/memos/commit/d688914b2864791eeadbf21c882608632875f17c)\n(`feat(auth): add SSO user identity linkage (#5883)`, boojack, 2026-04-23).\n\nThe fix removes the identifier-as-lookup-key branch and introduces an\nexternal-identity linkage:\n\n- New `user_identity` table via migration\n  `store/migration/{sqlite,mysql,postgres}/0.28/00__user_identity.sql`, with a\n  `(provider_uid, extern_uid)` unique constraint.\n- SSO lookup now goes through `resolveSSOUser()`, which resolves the local user\n  via the linkage table instead of `userInfo.Identifier`.\n- On the miss path, a local user is created with a UUID-based username derived\n  by `deriveSSOUsername()`, so the IdP identifier is no longer usable as a local\n  username key; the `(provider, extern_uid)` linkage is committed atomically\n  with the user.\n\nThe post-fix `SignIn` delegates to the helper:\n\n```go\n} else if ssoCredentials := request.GetSsoCredentials(); ssoCredentials != nil {\n    identityProvider, userInfo, err := s.resolveSSOIdentity(ctx, ssoCredentials.IdpName, ssoCredentials.Code, ssoCredentials.RedirectUri, ssoCredentials.CodeVerifier)\n    if err != nil { return nil, err }\n    user, err := s.resolveSSOUser(ctx, nil, identityProvider, userInfo)\n    if err != nil { return nil, err }\n    existingUser = user\n}\n```\n\n**Follow-up hardening (additional reference):**\n[`019f4f9a`](https://github.com/usememos/memos/commit/019f4f9adcfcfca73fc9e2a966d0569fac888a2c)\n(`fix(auth): provision SSO users atomically (#6114)`, shipped in v0.30.0) closes\na race in the linkage insert on concurrent first logins.\n\n## Remediation for Operators\n\nUpgrade to **v0.28.0 or later** (v0.30.0+ recommended, to include the atomic\nprovisioning fix). After upgrading, audit existing SSO-linked accounts.\n\n## Timeline\n\n- 2026-04-23 \u2014 fix `d688914b` merged (#5883), released in v0.28.0\n- v0.30.0 \u2014 follow-up hardening `019f4f9a` (#6114)\n- 2026-07-23 \u2014 CVE-2026-51584 reserved by MITRE\n\n## References\n\n- https://github.com/usememos/memos\n- https://github.com/usememos/memos/commit/d688914b2864791eeadbf21c882608632875f17c\n- https://github.com/usememos/memos/commit/019f4f9adcfcfca73fc9e2a966d0569fac888a2c\n", "creation_timestamp": "2026-08-11T04:57:17.905405Z"}</description>
      <content:encoded>{"uuid": "862e95b4-6bb7-417f-8e2a-c5b59e279a5d", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-51584", "type": "seen", "source": "https://gist.github.com/seiyaibuki0523/33a4c06eb7d10914e5e5152ecd5100ec", "content": "# CVE-2026-51584 \u2014 SSO Account Takeover in Memos (Missing External-Identity Binding)\n\n&amp;gt; Source-level security advisory. Memos' OAuth2/SSO sign-in resolved the local\n&amp;gt; account using the IdP-supplied identifier (username) as the sole lookup key,\n&amp;gt; with no binding to the IdP's stable subject. An attacker who controls their\n&amp;gt; identifier on any configured public IdP could take over an arbitrary local\n&amp;gt; account.\n\n## Summary\n\n| Field | Value |\n|---|---|\n| CVE | `CVE-2026-51584` |\n| Vulnerability type | Incorrect Access Control \u2192 Account Takeover (CWE-287 / CWE-284) |\n| Vendor / product | usememos / memos |\n| Affected component | `server/router/api/v1/auth_service.go` (`SignIn`, ssoCredentials branch) |\n| Affected versions | \u2264 v0.27.1 |\n| Fixed version | v0.28.0 |\n| Fixing commit | [`d688914b`](https://github.com/usememos/memos/commit/d688914b2864791eeadbf21c882608632875f17c) |\n| Attack type | Remote |\n| Impact | Escalation of privileges / account takeover |\n| Discoverer | Casper Chen, Cevanex |\n\n## Severity\n\n- **Severity:** High\n- **CVSS v3.1 (suggested):** `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N` \u2192 Base 9.1 *(inferred; not yet NVD-assigned)*\n- **Source:** inferred from source-level analysis, not NVD\n\nWhere SSO is enabled against a public IdP whose mapped identifier is\nattacker-controllable (username, email, preferred_username, or name), an\nattacker can authenticate as any existing local user, including admins \u2014\na full account takeover with no prior access to the victim account.\n\n## Root Cause\n\nIn the vulnerable `SignIn` handler, the SSO branch looked up the local user\nusing only the IdP-supplied identifier as the key:\n\n```go\n// server/router/api/v1/auth_service.go (v0.27.x, ssoCredentials branch)\nuser, err := s.Store.GetUser(ctx, &amp;amp;store.FindUser{\n    Username: &amp;amp;userInfo.Identifier,   // &amp;lt;-- only lookup key\n})\nif err != nil { /* ... */ }\nif user == nil {\n    // ... create new user with Username: userInfo.Identifier\n}\nexistingUser = user\n// existingUser is then passed to doSignIn(), which signs a JWT containing\n// existingUser.ID, existingUser.Username, existingUser.Role.\n```\n\nThere was **no** `user_identity` table or equivalent `(user_id, idp_id,\nexternal_sub)` binding. The IdP's stable `sub` claim was discarded \u2014\n`oauth2.IdentityProvider.UserInfo` populated only `Identifier` / `DisplayName`\n/ `Email` / `AvatarURL` from the configured `field_mapping`. By default and in\nevery documented example, `field_mapping.identifier` is `username`, `email`,\n`preferred_username`, or `name` \u2014 all attacker-controllable on any major public\nIdP.\n\nConsequently, an attacker who sets their identifier on the IdP to match a\nvictim's Memos username causes the lookup to resolve to the victim's local\naccount, and `doSignIn()` mints a valid session (JWT) for that account.\n\n## Proof of Concept\n\nPrerequisites: a Memos instance with OAuth2 SSO enabled against a public IdP,\nusing a default `field_mapping.identifier` (e.g. `email` or\n`preferred_username`), and knowledge of a victim's Memos username.\n\n1. On the configured IdP, set the account's mapped identifier field to the\n   victim's Memos username / email.\n2. Complete the standard OAuth2 authorization-code flow into Memos.\n3. During `SignIn`, `GetUser(FindUser{Username: &amp;amp;userInfo.Identifier})` resolves\n   to the **victim's** existing local user.\n4. `doSignIn()` issues an access token bound to the victim's ID / username /\n   role. The attacker now holds a valid session for the victim account.\n\n## The Fix\n\nFixed in **v0.28.0** by commit\n[`d688914b`](https://github.com/usememos/memos/commit/d688914b2864791eeadbf21c882608632875f17c)\n(`feat(auth): add SSO user identity linkage (#5883)`, boojack, 2026-04-23).\n\nThe fix removes the identifier-as-lookup-key branch and introduces an\nexternal-identity linkage:\n\n- New `user_identity` table via migration\n  `store/migration/{sqlite,mysql,postgres}/0.28/00__user_identity.sql`, with a\n  `(provider_uid, extern_uid)` unique constraint.\n- SSO lookup now goes through `resolveSSOUser()`, which resolves the local user\n  via the linkage table instead of `userInfo.Identifier`.\n- On the miss path, a local user is created with a UUID-based username derived\n  by `deriveSSOUsername()`, so the IdP identifier is no longer usable as a local\n  username key; the `(provider, extern_uid)` linkage is committed atomically\n  with the user.\n\nThe post-fix `SignIn` delegates to the helper:\n\n```go\n} else if ssoCredentials := request.GetSsoCredentials(); ssoCredentials != nil {\n    identityProvider, userInfo, err := s.resolveSSOIdentity(ctx, ssoCredentials.IdpName, ssoCredentials.Code, ssoCredentials.RedirectUri, ssoCredentials.CodeVerifier)\n    if err != nil { return nil, err }\n    user, err := s.resolveSSOUser(ctx, nil, identityProvider, userInfo)\n    if err != nil { return nil, err }\n    existingUser = user\n}\n```\n\n**Follow-up hardening (additional reference):**\n[`019f4f9a`](https://github.com/usememos/memos/commit/019f4f9adcfcfca73fc9e2a966d0569fac888a2c)\n(`fix(auth): provision SSO users atomically (#6114)`, shipped in v0.30.0) closes\na race in the linkage insert on concurrent first logins.\n\n## Remediation for Operators\n\nUpgrade to **v0.28.0 or later** (v0.30.0+ recommended, to include the atomic\nprovisioning fix). After upgrading, audit existing SSO-linked accounts.\n\n## Timeline\n\n- 2026-04-23 \u2014 fix `d688914b` merged (#5883), released in v0.28.0\n- v0.30.0 \u2014 follow-up hardening `019f4f9a` (#6114)\n- 2026-07-23 \u2014 CVE-2026-51584 reserved by MITRE\n\n## References\n\n- https://github.com/usememos/memos\n- https://github.com/usememos/memos/commit/d688914b2864791eeadbf21c882608632875f17c\n- https://github.com/usememos/memos/commit/019f4f9adcfcfca73fc9e2a966d0569fac888a2c\n", "creation_timestamp": "2026-08-11T04:57:17.905405Z"}</content:encoded>
      <guid isPermaLink="false">https://vulnerability.circl.lu/sighting/862e95b4-6bb7-417f-8e2a-c5b59e279a5d/export</guid>
      <pubDate>Tue, 11 Aug 2026 04:57:17 +0000</pubDate>
    </item>
    <item>
      <title>2a2e8416-038c-4092-885b-149d122a0823</title>
      <link>https://vulnerability.circl.lu/sighting/2a2e8416-038c-4092-885b-149d122a0823/export</link>
      <description>{"uuid": "2a2e8416-038c-4092-885b-149d122a0823", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-51583", "type": "seen", "source": "https://gist.github.com/seiyaibuki0523/d8af15eb555808319a2633269a9ebb80", "content": "# CVE-2026-51583 \u2014 Server-Side Request Forgery in Memos Webhook Dispatcher\n\n&amp;gt; Source-level security advisory. An authenticated user can coerce the Memos\n&amp;gt; backend into issuing HTTP requests to internal / unspecified addresses because\n&amp;gt; the webhook URL validator's reserved-CIDR list does not cover `0.0.0.0/8` and\n&amp;gt; several other non-routable ranges.\n\n## Summary\n\n| Field | Value |\n|---|---|\n| CVE | `CVE-2026-51583` |\n| Vulnerability type | Server-Side Request Forgery (CWE-918) |\n| Vendor / product | usememos / memos |\n| Affected component | `internal/webhook/validate.go` (`reservedCIDRs`), shared by `internal/webhook/webhook.go` |\n| Affected versions | \u2264 v0.30.0 (unpatched as of commit `9a928c28`) |\n| Fixed version | None \u2014 no patch available at time of publication |\n| Attack type | Remote, authenticated |\n| Impact | Bypass protection mechanism; internal service access via SSRF |\n| Discoverer | Casper Chen, Cevanex |\n\n## Severity\n\n- **Severity:** Medium\u2013High (depends on what internal services are reachable from the Memos container/host)\n- **CVSS v3.1 (suggested):** `AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N` \u2192 Base 8.5 *(inferred from code; not yet NVD-assigned)*\n- **Source:** inferred from source-level analysis and reproduction, not NVD\n\nAn authenticated, low-privilege user can create a webhook whose target is an\ninternal or unspecified address. When any memo event fires, the Memos backend\ndispatches an HTTP POST to that target from inside the trust boundary,\nreaching services that are not otherwise exposed (cloud metadata endpoints,\ninternal admin panels, other containers on the same network, etc.). The scope\nchange (S:C) reflects that the request originates from the server's network\nposition rather than the attacker's.\n\n## Root Cause\n\nWebhook target URLs are validated at registration time by `ValidateURL()` and\nagain at dispatch time by `safeDialContext()` (`internal/webhook/webhook.go`).\nBoth paths share a single `isReservedIP()` check backed by the `reservedCIDRs`\nlist in `internal/webhook/validate.go`.\n\nThat list is incomplete. It omits, among others:\n\n- `0.0.0.0/8` (unspecified \u2014 resolves to loopback on most stacks)\n- `::` (IPv6 unspecified)\n- `100.64.0.0/10` (CGNAT / shared address space)\n- `192.0.0.0/24` (IETF protocol assignments)\n- `198.18.0.0/15` (benchmarking)\n- multicast ranges\n\nBecause registration-time and dial-time validation reuse the same predicate,\na gap in the list bypasses **both** layers simultaneously. Reproduction against\nthe current tree confirms the gap:\n\n```\n0.0.0.0            blocked=false   lookup=[0.0.0.0]\n::                 blocked=false\n100.64.0.1         blocked=false   (CGNAT)\n192.0.0.1          blocked=false\n127.0.0.1          blocked=true\n```\n\n`127.0.0.1` is correctly blocked, but `0.0.0.0` \u2014 which most network stacks\nroute to loopback for outbound connections \u2014 sails through. The repository\ncurrently makes zero use of `net.IP.IsUnspecified`.\n\nThe bypassed control was introduced by\n[`150371d2`](https://github.com/usememos/memos/commit/150371d2111dfedd21483a21c49183079604d322)\n(`fix(webhook): remediate SSRF vulnerability in webhook dispatcher`,\n2026-02-23, shipped in v0.26.2 / v0.27.0; the file was later relocated from\n`plugin/webhook/validate.go` to `internal/webhook/validate.go` by `10a955fd`\nin v0.27.0). That commit added `reservedCIDRs` but left the ranges above\nuncovered, so the SSRF protection can still be bypassed.\n\n## Proof of Concept\n\n**Step 1 \u2014 start an internal listener inside the Memos container**\n\nSimulate an internally-bound service on port 9999.\n\n**Step 2 \u2014 register a malicious webhook**\n\nAs an authenticated user (e.g. User ID 2) with a valid access token, point the\nwebhook at the unspecified address:\n\n```bash\ncurl -X POST \"http://:5230/api/v1/users/2/webhooks\" \\\n    -H \"Authorization: Bearer \" \\\n    -H \"Content-Type: application/json\" \\\n    -d '{\n          \"displayName\": \"SSRF-Test\",\n          \"url\": \"http://0.0.0.0:9999\"\n        }'\n```\n\n**Step 3 \u2014 trigger dispatch**\n\nLog into the Memos web UI, create and publish a memo. This fires the webhook\nevent dispatcher.\n\n**Step 4 \u2014 verify**\n\nThe listener from Step 1 receives an HTTP POST from the Memos backend,\nconfirming the backend was coerced into contacting an internal address that\n`reservedCIDRs` failed to block.\n\n## Remediation\n\nNo upstream patch exists as of v0.30.0. Recommended fix:\n\nReplace or extend the `reservedCIDRs` check with a comprehensive predicate:\n\n```go\nip.IsUnspecified() || ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast()\n```\n\nand additionally block `100.64.0.0/10`, `192.0.0.0/24`, `198.18.0.0/15`, and\nmulticast. Because `ValidateURL()` and `safeDialContext()` share\n`isReservedIP()`, fixing the predicate closes both the registration-time and\ndispatch-time paths at once. Re-resolve DNS at dial time (or pin the resolved\nIP) to prevent DNS-rebinding from reintroducing the bypass.\n\n## Timeline\n\n- 2026-02-23 \u2014 `150371d2` introduces `reservedCIDRs` (incomplete range list)\n- 2026-04-18 \u2014 Privately reported to the vendor at `dev@usememos.com`, the channel designated in the project's `SECURITY.md`, with a working proof of concept\n- 2026-04-18 \u2013 2026-08-11 \u2014 No vendor response received (115 days)\n- 2026-07-23 \u2014 CVE-2026-51583 reserved by MITRE\n- 2026-08-11 \u2014 Publicly disclosed after exceeding the 90-day coordinated-disclosure window; unpatched as of commit `9a928c28`\n\n## References\n\n- https://github.com/usememos/memos\n- https://github.com/usememos/memos/commit/150371d2111dfedd21483a21c49183079604d322\n- https://github.com/usememos/memos/blob/main/internal/webhook/validate.go", "creation_timestamp": "2026-08-11T04:54:29.094470Z"}</description>
      <content:encoded>{"uuid": "2a2e8416-038c-4092-885b-149d122a0823", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-51583", "type": "seen", "source": "https://gist.github.com/seiyaibuki0523/d8af15eb555808319a2633269a9ebb80", "content": "# CVE-2026-51583 \u2014 Server-Side Request Forgery in Memos Webhook Dispatcher\n\n&amp;gt; Source-level security advisory. An authenticated user can coerce the Memos\n&amp;gt; backend into issuing HTTP requests to internal / unspecified addresses because\n&amp;gt; the webhook URL validator's reserved-CIDR list does not cover `0.0.0.0/8` and\n&amp;gt; several other non-routable ranges.\n\n## Summary\n\n| Field | Value |\n|---|---|\n| CVE | `CVE-2026-51583` |\n| Vulnerability type | Server-Side Request Forgery (CWE-918) |\n| Vendor / product | usememos / memos |\n| Affected component | `internal/webhook/validate.go` (`reservedCIDRs`), shared by `internal/webhook/webhook.go` |\n| Affected versions | \u2264 v0.30.0 (unpatched as of commit `9a928c28`) |\n| Fixed version | None \u2014 no patch available at time of publication |\n| Attack type | Remote, authenticated |\n| Impact | Bypass protection mechanism; internal service access via SSRF |\n| Discoverer | Casper Chen, Cevanex |\n\n## Severity\n\n- **Severity:** Medium\u2013High (depends on what internal services are reachable from the Memos container/host)\n- **CVSS v3.1 (suggested):** `AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N` \u2192 Base 8.5 *(inferred from code; not yet NVD-assigned)*\n- **Source:** inferred from source-level analysis and reproduction, not NVD\n\nAn authenticated, low-privilege user can create a webhook whose target is an\ninternal or unspecified address. When any memo event fires, the Memos backend\ndispatches an HTTP POST to that target from inside the trust boundary,\nreaching services that are not otherwise exposed (cloud metadata endpoints,\ninternal admin panels, other containers on the same network, etc.). The scope\nchange (S:C) reflects that the request originates from the server's network\nposition rather than the attacker's.\n\n## Root Cause\n\nWebhook target URLs are validated at registration time by `ValidateURL()` and\nagain at dispatch time by `safeDialContext()` (`internal/webhook/webhook.go`).\nBoth paths share a single `isReservedIP()` check backed by the `reservedCIDRs`\nlist in `internal/webhook/validate.go`.\n\nThat list is incomplete. It omits, among others:\n\n- `0.0.0.0/8` (unspecified \u2014 resolves to loopback on most stacks)\n- `::` (IPv6 unspecified)\n- `100.64.0.0/10` (CGNAT / shared address space)\n- `192.0.0.0/24` (IETF protocol assignments)\n- `198.18.0.0/15` (benchmarking)\n- multicast ranges\n\nBecause registration-time and dial-time validation reuse the same predicate,\na gap in the list bypasses **both** layers simultaneously. Reproduction against\nthe current tree confirms the gap:\n\n```\n0.0.0.0            blocked=false   lookup=[0.0.0.0]\n::                 blocked=false\n100.64.0.1         blocked=false   (CGNAT)\n192.0.0.1          blocked=false\n127.0.0.1          blocked=true\n```\n\n`127.0.0.1` is correctly blocked, but `0.0.0.0` \u2014 which most network stacks\nroute to loopback for outbound connections \u2014 sails through. The repository\ncurrently makes zero use of `net.IP.IsUnspecified`.\n\nThe bypassed control was introduced by\n[`150371d2`](https://github.com/usememos/memos/commit/150371d2111dfedd21483a21c49183079604d322)\n(`fix(webhook): remediate SSRF vulnerability in webhook dispatcher`,\n2026-02-23, shipped in v0.26.2 / v0.27.0; the file was later relocated from\n`plugin/webhook/validate.go` to `internal/webhook/validate.go` by `10a955fd`\nin v0.27.0). That commit added `reservedCIDRs` but left the ranges above\nuncovered, so the SSRF protection can still be bypassed.\n\n## Proof of Concept\n\n**Step 1 \u2014 start an internal listener inside the Memos container**\n\nSimulate an internally-bound service on port 9999.\n\n**Step 2 \u2014 register a malicious webhook**\n\nAs an authenticated user (e.g. User ID 2) with a valid access token, point the\nwebhook at the unspecified address:\n\n```bash\ncurl -X POST \"http://:5230/api/v1/users/2/webhooks\" \\\n    -H \"Authorization: Bearer \" \\\n    -H \"Content-Type: application/json\" \\\n    -d '{\n          \"displayName\": \"SSRF-Test\",\n          \"url\": \"http://0.0.0.0:9999\"\n        }'\n```\n\n**Step 3 \u2014 trigger dispatch**\n\nLog into the Memos web UI, create and publish a memo. This fires the webhook\nevent dispatcher.\n\n**Step 4 \u2014 verify**\n\nThe listener from Step 1 receives an HTTP POST from the Memos backend,\nconfirming the backend was coerced into contacting an internal address that\n`reservedCIDRs` failed to block.\n\n## Remediation\n\nNo upstream patch exists as of v0.30.0. Recommended fix:\n\nReplace or extend the `reservedCIDRs` check with a comprehensive predicate:\n\n```go\nip.IsUnspecified() || ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast()\n```\n\nand additionally block `100.64.0.0/10`, `192.0.0.0/24`, `198.18.0.0/15`, and\nmulticast. Because `ValidateURL()` and `safeDialContext()` share\n`isReservedIP()`, fixing the predicate closes both the registration-time and\ndispatch-time paths at once. Re-resolve DNS at dial time (or pin the resolved\nIP) to prevent DNS-rebinding from reintroducing the bypass.\n\n## Timeline\n\n- 2026-02-23 \u2014 `150371d2` introduces `reservedCIDRs` (incomplete range list)\n- 2026-04-18 \u2014 Privately reported to the vendor at `dev@usememos.com`, the channel designated in the project's `SECURITY.md`, with a working proof of concept\n- 2026-04-18 \u2013 2026-08-11 \u2014 No vendor response received (115 days)\n- 2026-07-23 \u2014 CVE-2026-51583 reserved by MITRE\n- 2026-08-11 \u2014 Publicly disclosed after exceeding the 90-day coordinated-disclosure window; unpatched as of commit `9a928c28`\n\n## References\n\n- https://github.com/usememos/memos\n- https://github.com/usememos/memos/commit/150371d2111dfedd21483a21c49183079604d322\n- https://github.com/usememos/memos/blob/main/internal/webhook/validate.go", "creation_timestamp": "2026-08-11T04:54:29.094470Z"}</content:encoded>
      <guid isPermaLink="false">https://vulnerability.circl.lu/sighting/2a2e8416-038c-4092-885b-149d122a0823/export</guid>
      <pubDate>Tue, 11 Aug 2026 04:54:29 +0000</pubDate>
    </item>
    <item>
      <title>6c4bd08a-6f04-4c7f-ae2f-b04e36fd0e86</title>
      <link>https://vulnerability.circl.lu/sighting/6c4bd08a-6f04-4c7f-ae2f-b04e36fd0e86/export</link>
      <description>{"uuid": "6c4bd08a-6f04-4c7f-ae2f-b04e36fd0e86", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-5158", "type": "seen", "source": "https://bsky.app/profile/atomicedge.bsky.social/post/3mshsfbxb772r", "content": "CVE-2026-5158 ultimate-post (CVSS Score 6.4) \n\n#WordPress plugin #vulnerability #cybersecurity #wordpressfirewall #hacking #wpsecurity #atomicedge #cybersecurity #malware #vulnerabilityresearch #cve #redteam #proofofconcept", "creation_timestamp": "2026-08-07T05:15:08.639266Z"}</description>
      <content:encoded>{"uuid": "6c4bd08a-6f04-4c7f-ae2f-b04e36fd0e86", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-5158", "type": "seen", "source": "https://bsky.app/profile/atomicedge.bsky.social/post/3mshsfbxb772r", "content": "CVE-2026-5158 ultimate-post (CVSS Score 6.4) \n\n#WordPress plugin #vulnerability #cybersecurity #wordpressfirewall #hacking #wpsecurity #atomicedge #cybersecurity #malware #vulnerabilityresearch #cve #redteam #proofofconcept", "creation_timestamp": "2026-08-07T05:15:08.639266Z"}</content:encoded>
      <guid isPermaLink="false">https://vulnerability.circl.lu/sighting/6c4bd08a-6f04-4c7f-ae2f-b04e36fd0e86/export</guid>
      <pubDate>Fri, 07 Aug 2026 05:15:08 +0000</pubDate>
    </item>
    <item>
      <title>0243217d-2ec1-4eda-ad45-e9f154348f2b</title>
      <link>https://vulnerability.circl.lu/sighting/0243217d-2ec1-4eda-ad45-e9f154348f2b/export</link>
      <description>{"uuid": "0243217d-2ec1-4eda-ad45-e9f154348f2b", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-5158", "type": "seen", "source": "https://bsky.app/profile/cve.skyfleet.blue/post/ipkrbhjyaww72", "content": "CVE-2026-5158 - PostX\nCVE ID : CVE-2026-5158\n \n Published : Aug. 6, 2026, 11:29 a.m. | 51\u00a0minutes ago\n \n Description : The Post Grid Gutenberg Blocks for News, Magazines, Blog Websites \u2013 PostX plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'inputPlac...", "creation_timestamp": "2026-08-06T12:22:36.371367Z"}</description>
      <content:encoded>{"uuid": "0243217d-2ec1-4eda-ad45-e9f154348f2b", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-5158", "type": "seen", "source": "https://bsky.app/profile/cve.skyfleet.blue/post/ipkrbhjyaww72", "content": "CVE-2026-5158 - PostX\nCVE ID : CVE-2026-5158\n \n Published : Aug. 6, 2026, 11:29 a.m. | 51\u00a0minutes ago\n \n Description : The Post Grid Gutenberg Blocks for News, Magazines, Blog Websites \u2013 PostX plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'inputPlac...", "creation_timestamp": "2026-08-06T12:22:36.371367Z"}</content:encoded>
      <guid isPermaLink="false">https://vulnerability.circl.lu/sighting/0243217d-2ec1-4eda-ad45-e9f154348f2b/export</guid>
      <pubDate>Thu, 06 Aug 2026 12:22:36 +0000</pubDate>
    </item>
  </channel>
</rss>
