Search: 1.2.4.4
44,562 threats
Most recently published first
| Severity | CVSS | Signals | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|---|
| High | 8.2 | EPSS 0.4% | CVE-2026-118665GraphQL Tools · Per-request connection parameters persist into later users' WebSocket authentications High8.2EPSS 0.4%GCVE DatabaseCVE-2026-118665 A vulnerability in the @graphql-tools/executor-legacy-ws package causes per-request WebSocket connection parameters to persist across different users. This stale authentication state leads to later users inheriting previous users' authentication credentials in the connection_init payload, potentially allowing unauthorized access to downstream GraphQL subscriptions. The issue affects versions prior to 1.1.36 and is fixed in version 1.1.36. | GCVE Database | ||
| Medium | 4.3 | EPSS 0.4% | CVE-2026-118667langchain-ai langgraph · Path Traversal Medium4.3EPSS 0.4%CVE Database V5CVE-2026-118667 A path traversal vulnerability (CWE-22) exists in langchain-ai's langgraph Python SDK and langgraph versions prior to 0.4.6 and 1.2.14 respectively. The issue arises when certain helper functions interpolate user-controlled assistant_id and thread_id values into authenticated GET request paths without proper encoding, allowing relative path segments to access unintended server paths. This vulnerability is fixed in langgraph-sdk 0.4.6 and langgraph 1.2.14. | CVE Database V5 | ||
| High | 8.2 | EPSS 0.3% | High8.2EPSS 0.3%CVE Database V5CVE-2026-118664 decode-uri-component provides a more robust alternative to decodeURIComponent. Prior to 0.5.1, decodeUriComponent in index.js falls back to customDecodeURIComponent after native decoding throws, and the fallback collects every distinct percent-encoded run before performing a full-string regular-expression replacement for each entry. Malformed input containing many distinct runs can therefore make both the number of replacements and the scanned input length grow together, causing quadratic CPU consumption and blocking the Node.js event loop; request-body inputs can reach the demonstrated size, while ordinary URL header limits reduce the practical delay. This issue is fixed in version 0.5.1. | CVE Database V5 | ||
| Medium | 5.3 | EPSS 0.4% | CVE-2026-118663honojs node-server · Double Decoding of the Same Data Medium5.3EPSS 0.4%CVE Database V5CVE-2026-118663 A vulnerability in honojs node-server versions from 1.19.10 up to but not including 2.1.3 allows an unauthenticated attacker to bypass middleware protections on static file serving. The issue arises because the serveStatic function decodes the request path a second time after initial decoding by Hono, leading to inconsistent path evaluation. This can cause the static file handler to serve files from within the configured static root directory that should be protected by middleware. The flaw does not allow directory traversal outside the static root. The vulnerability is fixed in version 2.1.3. | CVE Database V5 | ||
| Medium | 4.7 | EPSS 0.2% | CVE-2026-118658labstack echo · URL Redirection to Untrusted Site Medium4.7EPSS 0.2%CVE Database V5CVE-2026-118658 CVE-2026-118658 is an open redirect vulnerability in the labstack echo Go web framework. Versions prior to 4.15.2 and 5.1.1 allow an attacker to control the scheme used in redirects by manipulating certain forwarded scheme headers. This can lead to redirects using arbitrary URI schemes. The issue affects redirect middleware that uses Context.Scheme without validating the scheme. HTTPS-specific redirects are not affected. The vulnerability is fixed in versions 4.15.2 and 5.1.1. | CVE Database V5 | ||
| Critical | 9.1 | EPSS 0.2% | Critical9.1EPSS 0.2%CVE Database V5CVE-2026-117574 CVE-2026-117574 is an authorization bypass vulnerability in Red Hat OpenShift AI's ai-gateway-payload-processing component. An authenticated attacker can specify another tenant's model identifier in requests, causing the service to inject that tenant's API keys without verifying authorization. This allows unauthorized use of another tenant's large language model resources and quotas. Exploitation requires valid user credentials, limiting unauthenticated remote attacks. The vulnerability is rated critical with a CVSS score of 9.1. EPSS 0.2%Vulnerability | CVE Database V5 | ||
| High | 7.2 | EPSS 0.4% | High7.2EPSS 0.4%GCVE DatabaseCVE-2026-118250 ### Impact A dot-separated key path taken from `series.keys` is followed without filtering the individual segments. An attacker who controls `series.keys` and the matching point data can use a path such as `__proto__.polluted` to set arbitrary properties on `Object.prototype`. The resulting properties are visible to all JavaScript running in the page, not only to the chart. No user interaction is required beyond rendering the chart. The injected properties are inert until other code on the page reads them, so consequences depend on the consuming application. ### Workarounds Drop-in fix - for any versions affected (6.1.0-13.0.2). Add the below IIFE to run after Highcharts is loaded. ```javascript ((H)=>{const X = H.isObject;H.Point.prototype.setNestedProperty = function setNestedProperty(t,e,i){let s=i.split(".");return s.some(t=>"__proto__"===t||"constructor"===t)||s.reduce(function(t,i,s,o){let r=o.length-1===s;return t[i]=r?e:X(t[i],!0)?t[i]:{},t[i]},t),t};})(Highcharts); ``` [Live demo & testing](https://jsfiddle.net/BlackLabel/z3rbtm7u/) ### Obtaining the patched version The patched releases are available from all the usual distribution channels. With npm, upgrade the affected package to the patched version listed above, for example `npm install highcharts@13.1.1`. If you load Highcharts from the CDN, use the versioned URLs on code.highcharts.com, for example `https://code.highcharts.com/13.1.1/highcharts.js`. For more on each installation method, see the [installation guide](https://www.highcharts.com/docs/getting-started/installation). | GCVE Database | ||
| High | 7.2 | EPSS 0.4% | High7.2EPSS 0.4%GCVE DatabaseCVE-2026-118249 ### Impact When series columns are built from point objects, the point option keys are used directly as data column ids, so the write that populates a column reaches `Object.prototype` and the `Object` constructor. Keys named `__proto__` and `constructor` survive `JSON.parse` as own enumerable properties, so an attacker who controls the point objects can set integer-keyed properties on `Object.prototype`, one per point index, to values of their choosing. Named properties cannot be reached this way. The integer keys still affect every object in the page: reading an out-of-range index on any array or plain object returns the attacker's value, and `for...in` over any object yields the injected keys, so unrelated code can take branches it should not using attacker-supplied data, and rendering can fail as a side effect. The properties remain in place once the chart has been built, and no user interaction is required beyond rendering the chart. Consequences beyond disruption depend on the consuming application. ### Workarounds Drop-in fix - for any versions affected (6.1.0-13.0.2). Add the below IIFE to run after Highcharts is loaded. ```javascript ;!function(t){if(t&&t.Point&&!t.Point.prototype.protoPollutionPatched){var o=t.Point.prototype,r=o.optionsToObject,e=o.setNestedProperty,n=Object.prototype.hasOwnProperty;o.optionsToObject=function(t){if(t&&"object"==typeof t&&!Array.isArray(t)&&(n.call(t,"__proto__")||n.call(t,"constructor"))){var o={};for(var e in t)n.call(t,e)&&!c(e)&&(o[e]=t[e]);t=o}return r.call(this,t)},o.setNestedProperty=function(t,o,r){return String(r).split(".").some(c)?t:e.call(this,t,o,r)},o.protoPollutionPatched=!0}function c(t){return"__proto__"===t||"constructor"===t}}(Highcharts); ``` [Live demo & testing](https://jsfiddle.net/BlackLabel/nopc6vhj/) ### Obtaining the patched version The patched releases are available from all the usual distribution channels. With npm, upgrade the affected package to the patched version listed above, for example `npm install highcharts@13.1.0`. If you load Highcharts from the CDN, use the versioned URLs on code.highcharts.com, for example `https://code.highcharts.com/13.1.0/highcharts.js`. For more on each installation method, see the [installation guide](https://www.highcharts.com/docs/getting-started/installation). | GCVE Database | ||
| High | 8.4 | EPSS 0.3% | High8.4EPSS 0.3%GCVE DatabaseCVE-2026-118246 ### Impact The breadcrumbs `style` option is applied to the breadcrumb button as SVG attributes rather than as CSS, and the attribute names are not filtered. An attacker who controls the chart configuration can supply keys under `breadcrumbs.style` that name event handlers, and those keys become live handlers on the breadcrumb button, so the attacker's script runs in the origin of the page hosting the chart. The option is reached through `drilldown.breadcrumbs`, `navigation.breadcrumbs` and the `breadcrumbs` option of the treemap, sunburst and treegraph series. Exploitation requires that untrusted data reach the chart configuration and that a user drill down, or traverse into a level of a hierarchical series, so that the breadcrumbs render, and then hover over or activate the breadcrumb button. Charts rendered in styled mode do not apply the option and are not affected. Charts built with Highcharts Stock, Maps and Gantt are included, since those ship from the same package as Core. ### Workarounds Verified against published bundles on 10.0.0, 11.4.8, 12.3.0 and 13.0.2. Load immediately after Highcharts, before any chart is created: ```js // Workaround fix for all affected Highcharts versions: 10.0.0-13.0.2 ((H)=>{const S=H.SVGElement.prototype,D=S._defaultSetter;S._defaultSetter=function _defaultSetter(v,k,e){/^on/i.test(k)||D.call(this,v,k,e)};})(Highcharts); // End of the workaround fix ``` ### Obtaining the patched version The patched releases are available from all the usual distribution channels. With npm, upgrade the affected package to the patched version listed above, for example `npm install highcharts@13.1.0`. If you load Highcharts from the CDN, use the versioned URLs on code.highcharts.com, for example `https://code.highcharts.com/13.1.0/highcharts.js`. For more on each installation method, see the [installation guide](https://www.highcharts.com/docs/getting-started/installation). | GCVE Database | ||
| High | 8.6 | EPSS 0.3% | CVE-2026-118245Highcharts Dashboards · `chartConstructor` is an unchecked lookup into the Highcharts namespace High8.6EPSS 0.3%GCVE DatabaseCVE-2026-118245 ### Impact The Highcharts component uses the value of `chartConstructor` to select a function from the Highcharts namespace and invokes it with the component's container element and its `chartOptions`, without checking the value against the supported chart constructors. An attacker who controls the dashboard configuration can therefore name any other public member of that namespace; utility functions in that namespace copy the supplied options onto the container element as properties or attributes, so markup and event handlers carried in `chartOptions` land in the page and run in the origin of the page hosting the dashboard. Exploitation requires that untrusted data reach the Dashboards component configuration. No user interaction is required beyond rendering the board. ### Workarounds If your board configuration comes from a source you do not fully control, paste this snippet right after importing libraries: ```ts (function () { const HighchartsComponent = Dashboards && Dashboards.HighchartsComponent; if (!HighchartsComponent || !HighchartsComponent.prototype.createChart) { return; // HighchartsComponent not loaded } const allowedConstructors = [ 'chart', 'stockChart', 'mapChart', 'ganttChart' ]; const originalCreateChart = HighchartsComponent.prototype.createChart; HighchartsComponent.prototype.createChart = function () { if (allowedConstructors.indexOf(this.chartConstructor) === -1) { this.chartConstructor = 'chart'; } return originalCreateChart.apply(this, arguments); }; }()); ``` ### Obtaining the patched version The patched releases are available from all the usual distribution channels. With npm, upgrade the affected package to the patched version listed above, for example `npm install @highcharts/dashboards@4.2.2`. If you load Highcharts Dashboards from a CDN, use a versioned URL, for example `https://code.highcharts.com/dashboards/4.2.2/dashboards.js`. For more on each installation method, see the [installation guide](https://www.highcharts.com/docs/dashboards/installation). | GCVE Database | ||
| Medium | 6.9 | EPSS 0.4% | Medium6.9EPSS 0.4%GCVE Database ### Impact When a single cell value is written to a data table, the column id is used as a key on the table's column collection without filtering, so a column id of `__proto__` resolves to `Object.prototype`, is taken for an existing column, and the write lands at the row index on `Object.prototype`; a column id of `constructor` writes onto the `Object` constructor in the same way. In Dashboards releases that still supported column aliases, the id is first resolved through the alias map, so a literal `__proto__` id is redirected harmlessly there, while an alias whose target is `__proto__`, which the connector's data table options accept, reaches the same write. An attacker who controls the column id can thereby set integer-keyed properties on `Object.prototype`, one per row index, holding the written value; named properties cannot be reached through these paths, because the row index is a number. The integer keys still affect every object in the page: reading an out-of-range index on any array or plain object returns the injected value, and `for...in` over any object yields the injected keys, so unrelated code can take branches it should not using attacker-supplied data, and rendering can fail as a side effect. In Dashboards the write is reached through the Highcharts component's connector write-back, which is enabled by default through `allowConnectorUpdate` and takes the column id from the component's `columnAssignment`, or in the earliest releases from the series name, when a point is updated; in Grid Pro it is reached through cell editing in earlier releases and remains reachable through the public `DataTable` API. Exploitation requires that untrusted data reach the board or Grid configuration and that a point be updated or a cell edited, or that the application write a cell with an untrusted column id. Consequences beyond disruption depend on the consuming application. ### Workarounds Two measures are needed. The first closes the paths that reach `Object.prototype`; the second covers table construction, which cannot be patched from outside the library. #### 1. Strip unsafe keys from untrusted column data Apply this wherever column data enters your application, before it is handed to a grid, board or `DataTable`. This is the only measure that covers the `DataTable` constructor. ```js function stripUnsafeColumnIds(columns) { for (const key of ['__proto__', 'constructor']) { if (Object.prototype.hasOwnProperty.call(columns, key)) { delete columns[key]; } } return columns; } Grid.grid('container', { data: { columns: stripUnsafeColumnIds(untrustedColumns) } }); ``` #### 2. Patch the DataTable methods Needed if your application passes column ids that originate from untrusted input to `setCell`, `changeColumnId` or `setColumns`. Run it once at startup. ```js { const { DataTable } = Grid; // Or Dashboards if (!DataTable) { throw new Error('Patch loaded before Grid'); } const unsafe = (id) => id === '__proto__' || id === 'constructor'; const setCell = DataTable.prototype.setCell; DataTable.prototype.setCell = function (columnId, ...rest) { if (unsafe(columnId)) { return; } return setCell.call(this, columnId, ...rest); }; const changeColumnId = DataTable.prototype.changeColumnId; DataTable.prototype.changeColumnId = function (columnId, newColumnId) { if (unsafe(columnId) || unsafe(newColumnId)) { return false; } return changeColumnId.call(this, columnId, newColumnId); }; const setColumns = DataTable.prototype.setColumns; DataTable.prototype.setColumns = function (columns, ...rest) { const safe = {}; for (const key of Object.keys(columns || {})) { if (!unsafe(key)) { safe[key] = columns[key]; } } return setColumns.call(this, safe, ...rest); }; } ``` For npm, take `DataTable` from your import instead of the global — it is exported by Grid Lite, Grid Pro and Dashboards alike. ### Obtaining the patched version The patched releases are available from all the usual distribution channels. With npm, upgrade the affected package to the patched version listed above, for example `npm install @highcharts/dashboards@4.2.2`. If you load Highcharts Dashboards from a CDN, use a versioned URL, for example `https://code.highcharts.com/dashboards/4.2.2/dashboards.js`. For more on each installation method, see the [installation guide](https://www.highcharts.com/docs/dashboards/installation). | GCVE Database | ||
| Medium | 5.3 | EPSS 0.4% | CVE-2026-118243Highcharts Dashboards · `__proto__` data table id writes sync listeners to `Object.prototype` Medium5.3EPSS 0.4%GCVE DatabaseCVE-2026-118243 ### Impact The data cursor keeps its listener and state bookkeeping in plain objects keyed by data table id, so a table id of `__proto__` supplied in the `dataPool` connector configuration resolves to `Object.prototype` when a sync registers its listeners, and the registration creates a property on `Object.prototype` named after the sync state and holding the internal listener array. The property name begins with a state prefix fixed by the library, to which the sync `group` option can append an attacker-chosen suffix, and its value is the library's own listener array, but the property is enumerable and visible on every object in the page, and emitting a lasting state for that table id then throws, so syncs that keep lasting states, such as `extremes`, stop working. Exploitation requires that untrusted data reach the Dashboards configuration and that a sync such as `highlight` or `extremes` be enabled on a component using that table, which the same configuration can do. No user interaction is required beyond loading the board. The injected property is inert until other code on the page reads or enumerates it, so consequences depend on the consuming application. ### Workarounds **Drop-in fix - for any Highcharts Dashboards versions affected (1.0.0-4.2.1).** Add the below IIFE to run after Highcharts Dashboards is loaded. ``` !function(t){if(t&&t.DataCursor&&t.DataTable){var e=t.DataCursor.prototype,r=t.DataTable.prototype;e.tableIdPollutionPatched||(e.tableIdPollutionPatched=!0,null!==Object.getPrototypeOf((new t.DataCursor).listenerMap)&&['addListener','emitCursor','remitCursor','removeListener'].forEach(function(t){var r=e[t];r&&(e[t]=function(){var t;return t=this,['listenerMap','stateMap'].forEach(function(e){var r,a=t[e];a&&null!==Object.getPrototypeOf(a)&&(r=Object.create(null),Object.keys(a).forEach(function(t){r[t]=a[t]}),t[e]=r)}),r.apply(this,arguments)})}),'__proto__'!==new t.DataTable({id:'__proto__'}).id||Object.getOwnPropertyDescriptor(r,'id')||Object.defineProperty(r,'id',{configurable:!0,enumerable:!0,get:function(){return this.safeTableId},set:function(e){'__proto__'!==e&&'constructor'!==e||(e=t.uniqueKey(),this.autoId=!0),this.safeTableId=e}}))}}(Dashboards); ``` [Live demo & testing](https://jsfiddle.net/BlackLabel/jwqazb51/) ### Obtaining the patched version The patched releases are available from all the usual distribution channels. With npm, upgrade the affected package to the patched version listed above, for example `npm install @highcharts/dashboards@4.2.2`. If you load Highcharts Dashboards from a CDN, use a versioned URL, for example `https://code.highcharts.com/dashboards/4.2.2/dashboards.js`. For more on each installation method, see the [installation guide](https://www.highcharts.com/docs/dashboards/installation). | GCVE Database | ||
| High | 7.2 | EPSS 0.3% | CVE-2026-118244Highcharts Core · HTML text parsing falls back to unfiltered `innerHTML` during printing High7.2EPSS 0.3%GCVE DatabaseCVE-2026-118244 ### Impact When the HTML text parser cannot obtain a document from `DOMParser` because the call throws, it falls back to assigning the raw markup to the `innerHTML` of an element created in the hosting document, and the allow-list is applied only to the resulting DOM afterwards. In Chromium the Trusted Types policy callback that the parser uses throws while a `beforeprint` handler is running, so if the hosting page re-renders the chart from a `beforeprint` handler, every HTML-rendered text option parsed at that moment, such as `useHTML` titles, axis labels and data labels or text set by responsive rules, is inserted unsanitized, and event handlers embedded in that markup run in the origin of the page hosting the chart. Exploitation requires that untrusted data reach the chart configuration, that the hosting page update the chart from a `beforeprint` handler in Chromium, and that printing be started, which the print item of the exporting menu does on its own. Charts built with Highcharts Stock, Maps and Gantt are included, since those ship from the same package as Core. ### Workarounds **Drop-in fix - for any versions affected (12.0.0-13.0.2).** Add the below IIFE to run after Highcharts is loaded. ``` ((n)=>{n.AST.prototype.parseMarkup=function parseMarkup(t){let e,i=[];t=t.trim().replace(/ style=(["'])/g," data-style=$1");try{e=new DOMParser().parseFromString(tI?tI.createHTML(t):t,"text/html")}catch{}if(!e)try{e=new DOMParser().parseFromString(t,"text/html")}catch{}e||((e=n.doc.implementation.createHTMLDocument("")).body.innerHTML=t);let s=(t,e)=>{let i=t.localName||t.nodeName.toLowerCase(),o={tagName:i};"#text"===i&&(o.textContent=t.textContent||"");let r=t.attributes;if(r){let t={};[].forEach.call(r,e=>{"data-style"===e.name?o.style=tB.parseStyle(e.value):t[e.name]=e.value}),o.attributes=t}if(t.childNodes.length){let e=[];[].forEach.call(t.childNodes,t=>{s(t,e)}),e.length&&(o.children=e)}e.push(o)};return[].forEach.call(e.body.childNodes,t=>s(t,i)),i};})(Highcharts); ``` [Live demo & testing](https://jsfiddle.net/BlackLabel/pb6jLf7g/) ### Obtaining the patched version The patched releases are available from all the usual distribution channels. With npm, upgrade the affected package to the patched version listed above, for example npm install highcharts@13.1.0. If you load Highcharts from the CDN, use the versioned URLs on code.highcharts.com, for example https://code.highcharts.com/13.1.0/highcharts.js. For more on each installation method, see the [installation guide](https://www.highcharts.com/docs/getting-started/installation). | GCVE Database | ||
| High | 7.2 | EPSS 0.3% | CVE-2026-116796Highcharts Core: `javascript:` URL High7.2EPSS 0.3%GCVE DatabaseCVE-2026-116796 ### Impact The filter applied to markup in text options checks `href`, `src` and a few similar attributes against an allowed-scheme list, but accepts `xlink:href` without that check, so an SVG anchor whose `xlink:href` is a `javascript:` URL passes the filter, whether or not the option is rendered with `useHTML`. In the live page the attribute is written without the XLink namespace, so browsers do not treat the anchor as a link there. The attribute is preserved verbatim in the chart's serialised output: the SVG produced by the exporting module, including the default SVG download, declares the XLink namespace and contains the anchor, and so does the markup of the chart container. Any document that parses that output again, such as the downloaded SVG opened in a browser or a page that inlines exported or server-rendered chart markup, then holds a working link, and an attacker who controls the chart configuration can thereby run script in the origin of that document when a user activates the link. Exploitation requires that untrusted data reach a text option such as the title, that the chart be exported or its markup be serialised and parsed again, and that a user activate the link. ### Workarounds Drop-in fix for all affected versions (10.3.2 - 13.1.0). Add the below IIFE to run after Highcharts is loaded, before creating a chart. ``` !function(t){var e=t&&t.AST;if(e&&"function"==typeof e.filterUserAttributes&&!e.xlinkHrefPatched){var r=e.filterUserAttributes,n=Object.prototype.hasOwnProperty;e.filterUserAttributes=function(t){return t&&n.call(t,"xlink:href")&&!o(t["xlink:href"])&&delete t["xlink:href"],r.call(this,t)},e.xlinkHrefPatched=!0}function o(t){var r=e.allowedReferences||["https://","http://","mailto:","/","../","./","#"];return"string"==typeof t&&r.some(function(e){return 0===t.indexOf(e)})}}(Highcharts); ``` ### Obtaining the patched version The patched releases are available from all the usual distribution channels. With npm, upgrade the affected package to the patched version listed above, for example `npm install highcharts@13.1.1`. If you load Highcharts from the CDN, use the versioned URLs on code.highcharts.com, for example `https://code.highcharts.com/13.1.1/highcharts.js`. For more on each installation method, see the [installation guide](https://www.highcharts.com/docs/getting-started/installation). | GCVE Database | ||
| High | 7.5 | EPSS 0.4% | High7.5EPSS 0.4%GCVE DatabaseCVE-2026-118650 ## Summary When `middleware.Static` is mounted globally (`e.Use(middleware.Static(...))`) and an application relies on a **route- or group-level middleware guard** to restrict a path that also falls under the served static root, a `%2F`-encoded request bypasses that guard while the file is still served. This is the same encoding/decoding mismatch fixed for `StaticFS`/`StaticDirectoryHandler` in CVE-2026-55677 / GHSA-vfp3-v2gw-7wfq, but the fix did not cover the `middleware.Static` path. In addition, the `StaticConfig.EnablePathUnescaping` docstring states the default configuration prevents exactly this bypass, which is inaccurate for the global-mount case. **This is not path traversal:** no file outside the static root is accessed. The served file lives inside the static root; the issue is that access-control expectations set by a route guard are inconsistent between the literal and `%2F`-encoded forms of the same path. ## Details Root cause — the router and the static handler disagree on how to interpret `%2F`: - The router matches routes on the **raw, still-encoded** path, so `GET /admin%2Fsecret.txt` does **not** match a `/admin/...` route or group; any middleware attached to that route/group is therefore skipped. - `middleware.Static` selects its path source in `middleware/static.go` (~L219): with a global `e.Use` mount there is no wildcard route, so it uses `c.Request().URL.Path`, which `net/http` has already **decoded** (`%2F` → `/`). It then `path.Clean`s (~L235) and `Open`s (~L259) `admin/secret.txt`, serving the file. Net effect: for the literal path the guard runs; for the `%2F`-encoded path the guard is skipped but the same file is served. Relevant code: - `middleware/static.go` ~L219 (`p := c.Request().URL.Path`), ~L235 (`path.Clean`), ~L259 (`currentFS.Open`) - `StaticConfig.EnablePathUnescaping` docstring (`static.go` ~L60-67) — claims the default prevents the `/admin%2fprivate.txt` → `/admin/*` guard bypass; this is not true for the global mount. Relationship to prior advisories: - **CVE-2026-55677 / GHSA-vfp3-v2gw-7wfq** (patched 5.2.0): same `%2F` router-vs-handler mismatch, but fixed for `StaticFS`/`StaticDirectoryHandler`. The `middleware.Static` path was not covered — this report is that gap. - **CVE-2026-25766 / GHSA-pgvm-wxw2-hrv9** (patched 5.0.3): a *different* issue (Windows backslash traversal **outside** the root). Referenced only to disambiguate; not the same as this report. ## PoC Environment: `golang:1.25`, module using the official release (`go get github.com/labstack/echo/v5@v5.3.1`, no local `replace`). Static root `public/` contains a marker file `public/admin/secret.txt` = `SECRET`. Minimal app (the pattern under test: static served globally + a group guard intended to protect `/admin`): ```go package main import ( "net/http" "github.com/labstack/echo/v5" "github.com/labstack/echo/v5/middleware" ) func main() { e := echo.New() e.Use(middleware.Static("public")) // serves ./public globally (default filesystem) admin := e.Group("/admin", func(next echo.HandlerFunc) echo.HandlerFunc { return func(c *echo.Context) error { return c.String(http.StatusUnauthorized, "auth required") } }) admin.GET("/secret.txt", func(c *echo.Context) error { return c.String(http.StatusOK, "handler") }) e.Start(":1323") } ``` Requests (unauthenticated): ``` # Literal: route matches -> group guard runs curl -i http://localhost:1323/admin/secret.txt # => 401 # %2F-encoded: route does NOT match -> guard skipped, but middleware.Static serves the file curl -i --path-as-is http://localhost:1323/admin%2Fsecret.txt # => 200, body: SECRET ``` Observed on `v5.3.1`: literal → `401`; `%2F` → `200` with the file contents. For contrast, serving via the (patched) `e.StaticFS("/")` returns `404` for the same `%2F` request, showing the `middleware.Static` path was not covered by the CVE-2026-55677 fix. ## Impact An unauthenticated remote user can retrieve a file served by `middleware.Static` even when the application attached a route/group middleware guard to that path, by substituting `/` with `%2F`. The consequence is limited to files already inside the served static root (CWE-863 authorization inconsistency; CWE-436 interpretation conflict) — **there is no access to files outside the static root**. **Honest caveat on validity / severity:** this only has security impact for applications that (a) serve a directory statically to the public *and* (b) place a sensitive file inside that same directory while relying on a *route-level* guard to protect it. That combination is arguably a misconfiguration — a statically-served directory is public by design — so maintainers may reasonably classify this as a documentation fix (correct the `EnablePathUnescaping` claim) or won't-fix rather than a code vulnerability. It is filed primarily because (1) the router-vs-handler `%2F` inconsistency is the exact class fixed in CVE-2026-55677 but left uncovered for `middleware.Static`, and (2) the doc | GCVE Database | ||
| Medium | 6.1 | EPSS 0.2% | Medium6.1EPSS 0.2%GCVE DatabaseCVE-2026-118652 ### Summary The `Context.JSONP`, `Context.JSONPBlob`, and internal `jsonPBlob` helper in `context.go` directly concatenate the caller-supplied `callback` parameter into a JavaScript response **without any validation, escaping, or allow-listing**. This creates a high-impact **reflected XSS** that can be triggered by any route passing attacker-controlled data (query string, form, header, path param, etc.) into the callback. **Present in current master and v5.1.0 (latest release).** ### Vulnerable Code (verbatim) ```go func (c *Context) jsonPBlob(code int, callback string, i any) (err error) { c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8) c.response.WriteHeader(code) if _, err = c.response.Write([]byte(callback + "(")); err != nil { return } if err = c.echo.JSONSerializer.Serialize(c, i, ""); err != nil { return } if _, err = c.response.Write([]byte(");")); err != nil { return } return } func (c *Context) JSONP(code int, callback string, i any) (err error) { return c.jsonPBlob(code, callback, i) } func (c *Context) JSONPBlob(code int, callback string, b []byte) (err error) { c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8) c.response.WriteHeader(code) if _, err = c.response.Write([]byte(callback + "(")); err != nil { return } if _, err = c.response.Write(b); err != nil { return } _, err = c.response.Write([]byte(");")) return } ``` No sanitization is performed on the callback string. ### Exploit (one-request repro) Any route using the official pattern is vulnerable: ``` Goe.GET("/api", func(c echo.Context) error { return c.JSONP(200, c.QueryParam("callback"), map[string]string{"status": "ok"}) }) ``` Attacker request: ``` GET /api?callback=alert(document.domain)%2f%2f HTTP/1.1 Host: target.com ``` Server response: ``` Content-Type: application/javascript; charset=utf-8 alert(document.domain)//({"status":"ok"}); ``` → Immediate arbitrary JavaScript execution (full reflected XSS). ### Impact - Session hijacking, cookie theft, account takeover, keylogging, defacement. - Works even with strict CSP (response is served as application/javascript). #### Affected Versions - All versions ≤ v5.1.0 (including current master) #### Workarounds Manually sanitize the callback before calling JSONP/JSONPBlob: ``` Gofunc safeCallback(cb string) string { if matched, _ := regexp.MatchString(`^[a-zA-Z0-9_.\[\]]+$`, cb); !matched { return "callback" } return cb } ``` Or migrate away from JSONP entirely (use CORS + application/json). ### References - https://github.com/labstack/echo/blob/master/context.go - https://echo.labstack.com/docs/cookbook/jsonp ## Patches Fixed in `github.com/labstack/echo/v5` v5.4.0 and `github.com/labstack/echo/v4` v4.16.0. `Context.JSONP` and `Context.JSONPBlob` accept only a callback that is empty, a JavaScript identifier or a dot-separated path of identifiers (ASCII letters, digits, `_` and `$`); any other callback returns a 400 Bad Request error wrapping `ErrInvalidJSONPCallback` and nothing is written. JSONP responses also carry `X-Content-Type-Options: nosniff`. ## Workarounds Validate the callback in your handler before calling `Context.JSONP`, for example against `^[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)*$`, and set `X-Content-Type-Options: nosniff`. JSONP responses can be read by any website with the user's cookies, so do not serve data that requires authentication through JSONP. | GCVE Database | ||
| Medium | 5.3 | EPSS 0.4% | CVE-2026-118653V5 · Echo has Rate Limiter Bypass via Spoofed X-Forwarded-For Header in Default Configuration Medium5.3EPSS 0.4%GCVE DatabaseCVE-2026-118653 ## Summary When `echo.New()` is used without explicitly setting `Echo#IPExtractor`, the `RealIP()` method falls back to reading the client-supplied `X-Forwarded-For` (or `X-Real-IP`) header without any proxy-origin validation. The default `RateLimiter()` middleware derives its per-client identifier from `ctx.RealIP()`, so an attacker can rotate arbitrary values in the `X-Forwarded-For` header on each request to obtain a fresh rate-limit bucket and bypass IP-based throttling entirely. ## Affected Component - `context.go` — `(*Context).RealIP()` (lines 186–208), legacy fallback branch (lines 190–200) - `middleware/rate_limiter.go` — `DefaultRateLimiterConfig.IdentifierExtractor` (lines 46–58); `RateLimiter()` (lines 71–76) - `echo.go` — `New()` (lines 326–343), `IPExtractor` left `nil` by default ## Description ### `RealIP()` unconditionally trusts `X-Forwarded-For` when `IPExtractor` is unset `Context.RealIP()` (`context.go:186-208`) first checks `c.echo.IPExtractor`. When this field is `nil` (the default for `echo.New()`), it falls through to legacy behavior and returns the **first IP** from the `X-Forwarded-For` header — the position an attacker has full control over: ```go // context.go:186-200 func (c *Context) RealIP() string { if c.echo != nil && c.echo.IPExtractor != nil { return c.echo.IPExtractor(c.request) } // Fall back to legacy behavior if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" { i := strings.IndexAny(ip, ",") if i > 0 { xffip := strings.TrimSpace(ip[:i]) xffip = strings.TrimPrefix(xffip, "[") xffip = strings.TrimSuffix(xffip, "]") return xffip // ← attacker-controlled first IP } return ip } if ip := c.request.Header.Get(HeaderXRealIP); ip != "" { ... return ip // ← also attacker-controlled } ra, _, _ := net.SplitHostPort(c.request.RemoteAddr) return ra } ``` ### Rate limiter default identifier extractor calls `RealIP()` unconditionally `DefaultRateLimiterConfig` (`rate_limiter.go:46-58`) sets the identifier extractor to `ctx.RealIP()` with no guard for whether a safe `IPExtractor` is configured: ```go // rate_limiter.go:46-58 var DefaultRateLimiterConfig = RateLimiterConfig{ Skipper: DefaultSkipper, IdentifierExtractor: func(ctx *echo.Context) (string, error) { id := ctx.RealIP() // ← reads attacker-controlled header return id, nil }, ... } ``` `RateLimiter(store)` (`rate_limiter.go:71-76`) copies `DefaultRateLimiterConfig` directly: ```go // rate_limiter.go:71-76 func RateLimiter(store RateLimiterStore) echo.MiddlewareFunc { config := DefaultRateLimiterConfig config.Store = store return RateLimiterWithConfig(config) } ``` The result is that the most common usage pattern — `e.GET("/path", h, middleware.RateLimiter(store))` — produces a rate limiter whose per-client identifier is fully controlled by the requester. ### Framework acknowledges the issue for IP extraction but the rate limiter carries no warning `ip.go:27` explicitly states the default is insecure: > "Note: if you don't set `Echo#IPExtractor` explicitly, Echo fallback to legacy behavior, which is not a good choice." And `ip.go:117-119`: > "In default behavior, Echo sees all of first XFF header, X-Real-IP header and IP from network layer. As you might already notice, after reading this article, this is not good. Sole reason this is default is just backward compatibility." The `IPExtractor` mechanism (`ExtractIPDirect()`, `ExtractIPFromXFFHeader()`, `ExtractIPFromRealIPHeader()`) in `ip.go` exists precisely to close this gap. However, the `RateLimiter()` function and `DefaultRateLimiterConfig` have **no corresponding warning** and make no attempt to detect or flag that `IPExtractor` is unset, leaving operators who follow the standard rate limiter example silently exposed. The test `TestRateLimiterWithConfig_defaultConfig` (`rate_limiter_test.go:181-226`) itself drives the rate limiter by setting `X-Real-IP` directly on the test request — demonstrating that the identifier is freely injectable without comment or mitigation. ### Full execution chain 1. Server starts with `echo.New()` (no `IPExtractor` set) and `e.GET("/limited", h, middleware.RateLimiter(store))` 2. Attacker sends `GET /limited` with header `X-Forwarded-For: 1.2.3.4` — rate bucket for `1.2.3.4` consumed 3. Attacker sends `GET /limited` again with `X-Forwarded-For: 1.2.3.4` — second token consumed; if burst is 1, next request would be 429 4. Attacker sends `GET /limited` with `X-Forwarded-For: 5.6.7.8` — **new bucket created** for `5.6.7.8`, 200 OK returned 5. Attacker repeats step 4 with arbitrary IPs — rate limit never triggers; unlimited requests served ## Proof of Concept ```go package main import ( "net/http" echo "github.com/labstack/echo/v5" "github.com/labstack/echo/v5/middleware" ) func main() { e := echo.New() | GCVE Database | ||
| Medium | 5.3 | EPSS 0.2% | CVE-2026-118266V5 · Echo has CSRF Protection Bypass via MethodOverride Rewriting POST to Safe Method Medium5.3EPSS 0.2%GCVE DatabaseCVE-2026-118266 ## Summary The `MethodOverride` middleware accepts any non-empty string as the override target method — including safe methods (GET, HEAD, OPTIONS, TRACE) — when rewriting a POST request. When `MethodOverride` is registered before `CSRF` in the post-routing middleware chain (`e.Use()`), it rewrites the request method to a safe method before `CSRF` evaluates it. The CSRF middleware then skips token validation for the now-safe method, allowing state-changing POST handlers to execute without any CSRF check. Both the legacy token path and the modern `Sec-Fetch-Site` protection path are bypassed simultaneously. ## Affected Component - `middleware/method_override.go` — `MethodOverrideConfig.ToMiddleware()` (lines 55–71): no whitelist on the override target method - `middleware/csrf.go` — `CSRFConfig.ToMiddleware()` (lines 188–189): safe-method bypass branch reads the already-rewritten method - `middleware/csrf.go` — `checkSecFetchSiteRequest()` (line 283): `Sec-Fetch-Site` safe check also reads the rewritten method ## Description ### MethodOverride accepts safe methods as override targets `MethodOverrideConfig.ToMiddleware()` (`method_override.go:55-71`) restricts the **source** method (only POST requests are overrideable) but applies no whitelist to the **target**: ```go // method_override.go:61-67 req := c.Request() if req.Method == http.MethodPost { m := config.Getter(c) if m != "" { req.Method = m // ← any non-empty string accepted, including "GET" } } ``` The docstring's security claim — "For security reasons, only POST method can be overridden" — refers only to the source-method restriction. There is no guard preventing POST from being rewritten to `GET`, `HEAD`, `OPTIONS`, or `TRACE`. The test suite (`method_override_test.go`) only tests POST→DELETE and POST→PUT; POST→GET is never tested or blocked. ### CSRF safe-method branch reads the already-rewritten method `CSRFConfig.ToMiddleware()` (`csrf.go:188-189`) makes its validation decision based on `c.Request().Method` at the time it runs: ```go // csrf.go:188-189 switch c.Request().Method { case http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodTrace: // skip validation — no token check default: // validate CSRF token ``` If MethodOverride has already run and set `req.Method = "GET"`, this `switch` falls into the skip branch regardless of the original HTTP method or what handler was matched. The `Sec-Fetch-Site`-based path in `checkSecFetchSiteRequest()` (`csrf.go:283`) is identically vulnerable: ```go // csrf.go:283 isSafe := slices.Contains(safeMethods, c.Request().Method) ``` With `req.Method = "GET"` (already rewritten), `isSafe = true` and the function returns `true` — the request is allowed even when `Sec-Fetch-Site` is `cross-site`. **Both** CSRF protection paths are bypassed in a single step. ### Execution chain In `echo.go:700`, routing and middleware wrapping are performed in one step: ```go h = applyMiddleware(e.router.Route(c), e.middleware...) ``` 1. `e.router.Route(c)` evaluates with `req.Method = "POST"` → matches and binds the POST `/transfer` handler 2. `applyMiddleware` wraps it: `MethodOverride → CSRF → postHandler` At request execution time: 3. **MethodOverride** runs: `req.Method == "POST"` → reads form field `_method` = `"GET"` → `req.Method = "GET"` → calls `next` 4. **CSRF** runs: `c.Request().Method` = `"GET"` → `case http.MethodGet` → **skips token validation** → calls `next` 5. **postHandler** runs (the handler matched in step 1 — the original POST `/transfer` state-change handler) The state-changing handler executes with no CSRF token validation and with no `Sec-Fetch-Site` check. ### The missing target-method whitelist is the root cause The legitimate use case for MethodOverride is allowing HTML forms (which only support GET/POST) to send PUT, DELETE, or PATCH requests. There is no legitimate scenario in which an HTML form needs to rewrite POST to GET — that can always be expressed as an ordinary GET request. Allowing POST→GET (and HEAD/OPTIONS/TRACE) serves no valid purpose and is inherently dangerous when any safe-method-aware security middleware (CSRF, logging, audit) appears downstream. ## Proof of Concept ```go package main import ( "net/http" echo "github.com/labstack/echo/v5" "github.com/labstack/echo/v5/middleware" ) func main() { e := echo.New() // MethodOverride before CSRF — both in e.Use() (post-routing) e.Use(middleware.MethodOverrideWithConfig(middleware.MethodOverrideConfig{ Getter: middleware.MethodFromForm("_method"), })) e.Use(middleware.CSRF()) e.POST("/transfer", func(c *echo.Context) error { return c.String(http.StatusOK, "transfer executed") }) e.Logger.Fatal(e.Start(":18080")) } ``` ```bash # Baseline — CSRF correctly blocks a POST without a valid token curl -i -X POST 'http://127.0.0.1:18080/transfer' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data 'amount | GCVE Database |
Page 20 of 2,229 · 2 duplicate CVE records merged