Skip to content

Commit

Permalink
fix: ReDos regex vulnerability, reported by @dayshift (#515)
Browse files Browse the repository at this point in the history
  • Loading branch information
gr2m authored Feb 14, 2025
1 parent 0a80e82 commit 599ff4f
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ 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) => {
Expand Down
4 changes: 2 additions & 2 deletions src/util/extract-url-variable-names.ts
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down
102 changes: 102 additions & 0 deletions test/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,106 @@ 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.`,
);
}
});
});

0 comments on commit 599ff4f

Please sign in to comment.