Skip to content

Commit 6465e1b

Browse files
committed
fix(static): prevent path traversal via percent-encoded dot segments
1 parent 840ac5c commit 6465e1b

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

src/utils/static.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ export async function serveStatic(
8181
withLeadingSlash(withoutTrailingSlash(parseURL(event.path).pathname)),
8282
);
8383

84+
if (originalId.includes("..")) {
85+
if (!options.fallthrough) {
86+
throw createError({ statusCode: 404 });
87+
}
88+
return false;
89+
}
90+
8491
const acceptEncodings = parseAcceptEncoding(
8592
getRequestHeader(event, "accept-encoding"),
8693
options.encodings,

test/static.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { request as httpRequest } from "node:http";
12
import supertest, { SuperTest, Test } from "supertest";
23
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
34
import {
@@ -108,4 +109,32 @@ describe("Serve Static", () => {
108109
const res = await request.post("/test.png");
109110
expect(res.status).toEqual(405);
110111
});
112+
113+
it("Prevents path traversal via percent-encoded dot segments", async () => {
114+
const listener = toNodeListener(app);
115+
const server = await import("node:http").then((m) =>
116+
m.createServer(listener),
117+
);
118+
await new Promise<void>((resolve) => server.listen(0, resolve));
119+
const port = (server.address() as any).port;
120+
try {
121+
const res = await new Promise<{ statusCode: number }>((resolve) => {
122+
httpRequest(
123+
{
124+
hostname: "127.0.0.1",
125+
port,
126+
path: "/%2e%2e/%2e%2e/etc/passwd",
127+
method: "GET",
128+
},
129+
(res) => resolve({ statusCode: res.statusCode! }),
130+
).end();
131+
});
132+
expect(serveStaticOptions.getMeta).not.toHaveBeenCalledWith(
133+
expect.stringContaining(".."),
134+
);
135+
expect(res.statusCode).toEqual(404);
136+
} finally {
137+
server.close();
138+
}
139+
});
111140
});

0 commit comments

Comments
 (0)