CVE-2025-25285
Description
@octokit/endpoint turns REST API endpoints into generic request options. Starting in version 4.1.0 and prior to version 10.1.3, by crafting specific options parameters, the endpoint.parse(options) call can be triggered, leading to a regular expression denial-of-service (ReDoS) attack. This causes the program to hang and results in high CPU utilization. The issue occurs in the parse function within the parse.ts file of the npm package @octokit/endpoint. Version 10.1.3 contains a patch for the issue.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
@octokit/endpointnpm | >= 9.0.5, < 9.0.6 | 9.0.6 |
@octokit/endpointnpm | >= 10.0.0, < 10.1.3 | 10.1.3 |
Patches
2d6cf1ad777b26c9c5be033c4Merge commit from fork
3 files changed · +93 −3
src/parse.ts+1 −1 modified@@ -59,7 +59,7 @@ export function parse(options: EndpointDefaults): RequestOptions { if (url.endsWith("/graphql")) { if (options.mediaType.previews?.length) { const previewsFromAcceptHeader = - headers.accept.match(/[\w-]+(?=-preview)/g) || ([] as string[]); + headers.accept.match(/(?<![\w-])[\w-]+(?=-preview)/g) || ([] as string[]); headers.accept = previewsFromAcceptHeader .concat(options.mediaType.previews!) .map((preview) => {
src/util/extract-url-variable-names.ts+2 −2 modified@@ -1,7 +1,7 @@ -const urlVariableRegex = /\{[^}]+\}/g; +const urlVariableRegex = /\{[^{}}]+\}/g; function removeNonChars(variableName: string) { - return variableName.replace(/^\W+|\W+$/g, "").split(/,/); + return variableName.replace(/(?:^\W+)|(?:(?<!\W)\W+$)/g, "").split(/,/); } export function extractUrlVariableNames(url: string) {
test/parse.test.ts+90 −0 modified@@ -52,4 +52,94 @@ describe("endpoint.parse()", () => { expect(input.headers.accept).toEqual("application/vnd.github.v3+json"); }); + + it("Test ReDoS - attack string #1", async () => { + const startTime = performance.now(); + try { + endpoint.parse({ + method: "POST", + url: "/graphql", // Ensure that the URL ends with "/graphql" + headers: { + accept: "" + "A".repeat(100000) + "-", // Pass in the attack string + "content-type": "text/plain", + "user-agent": "Your User Agent String Here", + }, + mediaType: { + previews: ["test-preview"], // Ensure that mediaType.previews exists and has values + format: "raw", // Optional media format + }, + baseUrl: "https://api.github.com", + }); + } catch (error) { + // pass + } + const endTime = performance.now(); + const elapsedTime = endTime - startTime; + const reDosThreshold = 2000; + + expect(elapsedTime).toBeLessThanOrEqual(reDosThreshold); + if (elapsedTime > reDosThreshold) { + console.warn(`🚨 Potential ReDoS Attack! getDuration method took ${elapsedTime.toFixed(2)} ms, exceeding threshold of ${reDosThreshold} ms.`); + } + }); + + it("Test ReDoS - attack string #2", async () => { + const startTime = performance.now(); + try { + endpoint.parse({ + method: "POST", + url: "{".repeat(100000) + "@", // Pass in the attack string + headers: { + accept: "application/vnd.github.v3+json", + "content-type": "text/plain", + "user-agent": "Your User Agent String Here", + }, + mediaType: { + previews: ["test-preview"], // Ensure that mediaType.previews exists and has values + format: "raw", // Optional media format + }, + baseUrl: "https://api.github.com", + }); + } catch (error) { + // pass + } + const endTime = performance.now(); + const elapsedTime = endTime - startTime; + const reDosThreshold = 2000; + + expect(elapsedTime).toBeLessThanOrEqual(reDosThreshold); + if (elapsedTime > reDosThreshold) { + console.warn(`🚨 Potential ReDoS Attack! getDuration method took ${elapsedTime.toFixed(2)} ms, exceeding threshold of ${reDosThreshold} ms.`); + } + }); + + it("Test ReDoS - attack string #3", async () => { + const startTime = performance.now(); + try { + endpoint.parse({ + method: "POST", + url: "{"+"00"+"\u0000".repeat(100000)+"a!a"+"}", // Pass in the attack string + headers: { + accept: "application/vnd.github.v3+json", + "content-type": "text/plain", + "user-agent": "Your User Agent String Here", + }, + mediaType: { + previews: ["test-preview"], + format: "raw", + }, + baseUrl: "https://api.github.com", + }); + } catch (error) { + // pass + } + const endTime = performance.now(); + const elapsedTime = endTime - startTime; + const reDosThreshold = 2000; + + expect(elapsedTime).toBeLessThanOrEqual(reDosThreshold); + if (elapsedTime > reDosThreshold) { + console.warn(`🚨 Potential ReDoS Attack! getDuration method took ${elapsedTime.toFixed(2)} ms, exceeding threshold of ${reDosThreshold} ms.`); + } + }); });
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-x4c5-c7rf-jjgvghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-25285ghsaADVISORY
- github.com/octokit/endpoint.js/blob/main/src/parse.tsnvdWEB
- github.com/octokit/endpoint.js/commit/6c9c5be033c450d436efb37de41b6470c22f7db8nvdWEB
- github.com/octokit/endpoint.js/security/advisories/GHSA-x4c5-c7rf-jjgvnvdWEB
News mentions
0No linked articles in our index yet.