Skip to content

Commit 3cb65de

Browse files
committed
Fix path traversal in path
1 parent 3f1c3a7 commit 3cb65de

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

library/agent/Source.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const SOURCES = [
88
"xml",
99
"subdomains",
1010
"markUnsafe",
11+
"url",
1112
] as const;
1213

1314
export type Source = (typeof SOURCES)[number];

library/sources/HTTPServer.test.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import * as fetchBlockedLists from "../agent/api/fetchBlockedLists";
1313
import { mkdtemp, writeFile, unlink } from "fs/promises";
1414
import { exec } from "child_process";
1515
import { promisify } from "util";
16+
import { FileSystem } from "../sinks/FileSystem";
17+
import { Path } from "../sinks/Path";
1618
const execAsync = promisify(exec);
1719

1820
// Before require("http")
@@ -48,7 +50,7 @@ const agent = createTestAgent({
4850
token: new Token("123"),
4951
api,
5052
});
51-
agent.start([new HTTPServer()]);
53+
agent.start([new HTTPServer(), new FileSystem(), new Path()]);
5254

5355
wrap(fetchBlockedLists, "fetchBlockedLists", function fetchBlockedLists() {
5456
return async function fetchBlockedLists(): Promise<{
@@ -78,6 +80,7 @@ t.beforeEach(() => {
7880

7981
const http = require("http") as typeof import("http");
8082
const https = require("https") as typeof import("https");
83+
const { readFileSync } = require("fs");
8184

8285
t.test("it wraps the createServer function of http module", async () => {
8386
const server = http.createServer((req, res) => {
@@ -719,3 +722,61 @@ t.test(
719722
});
720723
}
721724
);
725+
726+
t.test("it blocks path traversal in path", async (t) => {
727+
const server = http.createServer((req, res) => {
728+
try {
729+
// @ts-expect-error Ignore
730+
const file = readFileSync(join(__dirname, req.url));
731+
732+
res.statusCode = 200;
733+
res.end(file);
734+
} catch (error) {
735+
res.statusCode = 500;
736+
if (error instanceof Error) {
737+
res.end(error.message);
738+
return;
739+
}
740+
res.end("Internal server error");
741+
}
742+
});
743+
744+
await new Promise<void>((resolve) => {
745+
server.listen(3327, async () => {
746+
const response = await new Promise((resolve, reject) => {
747+
const req = http.request(
748+
{
749+
hostname: "localhost",
750+
port: 3327,
751+
path: "/../package.json", // Path traversal attempt
752+
method: "GET",
753+
},
754+
(res) => {
755+
let data = "";
756+
757+
res.on("data", (chunk) => {
758+
data += chunk;
759+
});
760+
761+
res.on("end", () => {
762+
resolve(data);
763+
});
764+
}
765+
);
766+
767+
req.on("error", (err) => {
768+
reject(err);
769+
});
770+
771+
req.end();
772+
});
773+
774+
t.equal(
775+
response,
776+
"Zen has blocked a path traversal attack: path.join(...) originating from url."
777+
);
778+
server.close();
779+
resolve();
780+
});
781+
});
782+
});

0 commit comments

Comments
 (0)