Skip to content

Commit e1e4489

Browse files
authored
fix: ReDos regex vulnerability, reported by @dayshift (#660)
1 parent 5b84386 commit e1e4489

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

src/iterator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export function iterator(
3737
// '<https://api.github.com/users/aseemk/followers?page=2>; rel="next", <https://api.github.com/users/aseemk/followers?page=2>; rel="last"'
3838
// sets `url` to undefined if "next" URL is not present or `link` header is not set
3939
url = ((normalizedResponse.headers.link || "").match(
40-
/<([^>]+)>;\s*rel="next"/,
40+
/<([^<>]+)>;\s*rel="next"/,
4141
) || [])[1];
4242

4343
return { value: normalizedResponse };

test/paginate.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,44 @@ const ORG2 = { id: 2 };
99

1010
const TestOctokit = Octokit.plugin(paginateRest, restEndpointMethods);
1111
describe("pagination", () => {
12+
it("Test ReDoS - attack string", async () => {
13+
const ReDosOctokit = Octokit.plugin(paginateRest);
14+
const octokit = new ReDosOctokit({
15+
auth: "your-github-token",
16+
});
17+
octokit.hook.wrap("request", async () => {
18+
const maliciousLinkHeader = "" + "<".repeat(100000) + ">";
19+
return {
20+
data: [],
21+
headers: {
22+
link: maliciousLinkHeader,
23+
},
24+
status: 200,
25+
url: "",
26+
};
27+
});
28+
const startTime = performance.now();
29+
try {
30+
for await (const normalizedResponse of octokit.paginate.iterator(
31+
"GET /repos/{owner}/{repo}/issues",
32+
{ owner: "DayShift", repo: "ReDos", per_page: 100 },
33+
)) {
34+
normalizedResponse;
35+
}
36+
} catch (error) {
37+
// pass
38+
}
39+
const endTime = performance.now();
40+
const elapsedTime = endTime - startTime;
41+
const reDosThreshold = 2000;
42+
43+
expect(elapsedTime).toBeLessThanOrEqual(reDosThreshold);
44+
if (elapsedTime > reDosThreshold) {
45+
console.warn(
46+
`🚨 Potential ReDoS Attack! getDuration method took ${elapsedTime.toFixed(2)} ms, exceeding threshold of ${reDosThreshold} ms.`,
47+
);
48+
}
49+
});
1250
it(".paginate()", async () => {
1351
const mock = fetchMock
1452
.sandbox()

0 commit comments

Comments
 (0)