Recently while fuzzing Node.js modules I found an issue which causes the process to abort when malformed Windows UNC style paths are passed into pathToFileURL(). This was initially something I looked at as a potential security issue due to the crash behavior, but after discussion with the Node.js security / WG team it was considered a bug and tracked publicly. I ended up opening a github issue here: https://github.com/nodejs/node/issues/62546
I was fuzzing path / URL related functionality inside Node.js. The input which triggered the issue was:
1
\\exa mple\share\file.txt
Passing this into:
1
require('node:url').pathToFileURL(...)
Proof of Concept
1
node -e "require('node:url').pathToFileURL('\\\\\\\\exa mple\\\\share\\\\file.txt',{windows:true})"
Result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
snoopy@snoopy-MacBookPro11-4:~/$ node -e "require('node:url').pathToFileURL('\\\\\\\\exa mple\\\\share\\\\file.txt',{windows:true})"; echo $?
# node[95573]: static void node::url::BindingData::PathToFileURL(const FunctionCallbackInfo<Value> &) at ../src/node_url.cc:172
# Assertion failed: out->set_hostname(hostname.ToStringView())
----- Native stack trace -----
1: 0x90ace8 node::Assert(node::AssertionInfo const&) [node]
2: 0xa2a2b7 node::url::BindingData::PathToFileURL(v8::FunctionCallbackInfo<v8::Value> const&) [node]
3: 0x771269d8fb4d
----- JavaScript stack trace -----
1: URL (node:internal/url:825:20)
2: pathToFileURL (node:internal/url:1659:12)
3: pathToFileURL (node:url:1022:10)
4: [eval]:1:21
5: runScriptInThisContext (node:internal/vm:219:10)
6: node:internal/process/execution:483:12
7: [eval]-wrapper:6:24
8: runScriptInContext (node:internal/process/execution:481:60)
9: evalFunction (node:internal/process/execution:315:30)
10: evalTypeScript (node:internal/process/execution:327:3)
Aborted (core dumped)
134
Instead of throwing a normal JavaScript exception, Node aborts from native code.
What pathToFileURL() Does
pathToFileURL() converts filesystem paths into file:// URLs.
Examples:
1
pathToFileURL('/tmp/test.txt')
Returns:
1
file:///tmp/test.txt
Windows examples:
1
pathToFileURL('C:\\test.txt')
Returns:
1
file:///C:/test.txt
UNC paths such as:
1
\\server\share\file.txt
Need special handling and become:
1
file://server/share/file.txt
So internally Node needs to parse:
- hostname
- share path
- separators
- validity of hostnames
That is where malformed input becomes interesting.
Root Cause
The malformed hostname section:
1
exa mple
contains a space.
Somewhere during native processing this eventually reaches:
1
out->set_hostname(hostname.ToStringView())
Which triggers an assertion rather than rejecting the input gracefully.
Expected behavior:
- throw exception
- reject invalid UNC host
Actual behavior:
- process aborts
If user-controlled input reaches affected code paths, an attacker may be able to crash a Node.js process.
That could mean:
- CLI tooling crash
- worker restart loops
- service instability
- availability impact
Even when not considered a security issue upstream, process aborts are still worth fixing. After the initial crash, I checked where else pathToFileURL() was used internally.
Multiple places were interesting.
1) CLI Entry Path Handling
Node startup path handling uses:
1
pathToFileURL(mainPath)
Inside:
1
lib/internal/modules/run_main.js
2) node –check
Syntax checking flow also reaches:
1
pathToFileURL(filename)
Inside:
1
lib/internal/main/check_syntax.js
3) VM Dynamic Import Referrer
This path was interesting:
1
2
3
4
5
6
7
const vm = require('node:vm');
new vm.Script('import("node:fs")', {
filename: process.argv[2],
importModuleDynamically:
vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
}).runInThisContext();
If filename is attacker controlled, it can flow into referrer normalization using pathToFileURL().
4) Public node:module APIs
Two public APIs also reached the same sink.
1
Module.findPackageJSON(..., base)
and
1
Module.findSourceMap(sourceURL)
The easiest trigger was:
1
2
const Module = require("node:module");
Module.findSourceMap(process.argv[2]);
Run:
1
2
3
node run.js "\\ex ample\\share\\file.txt"
Crash.
I also reproduced this on Windows where the process aborted with the same assertion stack trace. You can see it below
I initially tried to report it through HackerOne under the Node.js program. However, low signal restrictions in hackerone prevented submission. After that I contacted the Node.js security / WG folks through their Slack channels and shared details. Their view was that this should be treated as a bug rather than a security issue.
That is fair from a triage perspective:
- no RCE
- no memory corruption
- no privilege escalation
- controlled malformed input causes abort
Still, if externally reachable, crashes can matter operationally. This was a fun find because it started as random fuzzing and turned into:
- root cause review
- call graph tracing
- multiple reachable sinks
- upstream bug confirmation
Sometimes the best bugs are not flashy memory corruption bugs.Sometimes it is just one malformed path and an assertion waiting behind it. Learning security while segfaulting through life.

