From f0deca71de6659da1b4dfb211a88c092943a9bca Mon Sep 17 00:00:00 2001 From: Cid-oe Date: Wed, 9 Sep 2026 23:07:18 +0530 Subject: [PATCH] fix(trace): exclude non-HTTP URL schemes like data: URLs from HTTP accesses --- packages/trace/src/index.ts | 16 ++++++++++++---- tests/trace.test.mjs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/packages/trace/src/index.ts b/packages/trace/src/index.ts index 59b0d32..bd8bb2e 100644 --- a/packages/trace/src/index.ts +++ b/packages/trace/src/index.ts @@ -160,10 +160,18 @@ function recordFileAccess(access: "read" | "write", selector: fs.PathOrFileDescr } function fetchSelector(input: Parameters[0]): string | undefined { - if (typeof input === "string") return input; - if (input instanceof URL) return input.toString(); - if (typeof Request !== "undefined" && input instanceof Request) return input.url; - return undefined; + let raw: string | undefined; + if (typeof input === "string") raw = input; + else if (input instanceof URL) raw = input.toString(); + else if (typeof Request !== "undefined" && input instanceof Request) raw = input.url; + if (!raw) return undefined; + try { + const parsed = new URL(raw, "http://cellfence.local"); + if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return undefined; + } catch { + return undefined; + } + return raw; } // 0.4.x (N-13): snapshot the disable flag at module-load time. diff --git a/tests/trace.test.mjs b/tests/trace.test.mjs index 1f21e84..9a16788 100644 --- a/tests/trace.test.mjs +++ b/tests/trace.test.mjs @@ -558,6 +558,43 @@ test("trace hook ignores fetch inputs that do not expose a URL selector", () => assert.deepEqual(evidence.accesses, []); }); +test("trace hook ignores fetch calls with non-HTTP schemes like data: URLs", () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "cellfence-trace-fetch-non-http-")); + fs.writeFileSync(path.join(tempDir, "app.mjs"), ` + try { + await fetch("data:text/plain,hello"); + } catch {} + try { + await fetch(new URL("data:application/json,%7B%22ok%22%3Atrue%7D")); + } catch {} + try { + await fetch("https://example.invalid/valid-http"); + } catch {} + `); + + const evidencePath = path.join(tempDir, "resource-evidence.json"); + const result = spawnSync(process.execPath, [ + "--import", + pathToFileURL(tracePath).href, + "app.mjs", + ], { + cwd: tempDir, + encoding: "utf8", + env: { + ...process.env, + CELLFENCE_TRACE_CELL: "runtime", + CELLFENCE_TRACE_OUT: evidencePath, + }, + }); + + assert.equal(result.status, 0, result.stderr); + const evidence = JSON.parse(fs.readFileSync(evidencePath, "utf8")); + assert.equal(evidence.transcriptStatus, "active"); + assert.deepEqual(evidence.accesses.map((access) => access.selector), [ + "https://example.invalid/valid-http", + ]); +}); + test("trace hook covers default cell/output and fd based skips", () => { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "cellfence-trace-defaults-")); fs.mkdirSync(path.join(tempDir, "data"), { recursive: true });