You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Null bytes in url could cause some problems #39592
Uncaught TypeError [ERR_INVALID_URL]: Invalid URL
at __node_internal_captureLargerStackTrace (node:internal/errors:464:5)
at new NodeError (node:internal/errors:371:5)
at onParseError (node:internal/url:536:9)
at new URL (node:internal/url:612:5) {
input: 'a',
code: 'ERR_INVALID_URL'
The error input is apprently truncated by the null byte.
How often does it reproduce? Is there a required condition?
I think this could only happen when attacker is trying to bypass some SSRF filter in some scenario, but I think it is almost unlikely to happen in realworld.
consturl=require('url')consthttp=require('http')constu=url.parse('http://[127.0.0.1\0.github.io]:8000/')console.log(u)if(!u.hostname.endsWith('.github.io')){console.log('Sorry, you can only fetch *.github.io')process.exit(1)}http.request({host: u.hostname,// null byte truncatedport: u.port,path: u.path,headers: {Host: 'xx'// http will automatically set host header by default, and \0 will cause an error in header}},msg=>{msg.on('data',data=>{console.log(data.toString())})}).on('error',console.error).end()
What is the expected behavior?
It should be invalid url, and http module shouldn't accept null byte.
What do you see instead?
Parsed successfully into a hostname with null byte.
The second bug described here, where new URL('a\0b') reports the input as 'a' in the error message, originates in the C++ code. The null character gets treated as the end-of-string marker, but only in the error path. It gets encoded and handled correctly, for example, in new URL('http://example.com/a\0b'). (Safari and Firefox also handle that last one correctly, but Chrome throws. I believe Chrome is deviating from the spec, but even if I'm wrong about that, for the purposes of this conversation, it doesn't matter.)
Possible solutions:
Use std::string instead of char * and then be very careful so we can preserve the NULL. (I suppose this approach might not work depending on the nature of how the string is handled elsewhere in the C++ code.)
Don't report the input string that caused the error back to the user. (Chrome and Safari both take this route.)
Don't worry about it. Report the truncated string. (Firefox takes this approach.)
Preserve the input in JavaScript and re-use it when an error is thrown from C++.
The WHATWG URL error message issue has been fixed. The legacy url.parse() has several possible solutions. I think the best is to bail on parsing when there is a NULL character (and possibly other C0 characters) in the host (and possibly a few other places?) and return an object with only path/pathname/href values set to anything other than null.
The WHATWG URL error message issue has been fixed. The legacy url.parse() has several possible solutions. I think the best is to bail on parsing when there is a NULL character (and possibly other C0 characters) in the host (and possibly a few other places?) and return an object with only path/pathname/href values set to anything other than null.
Looks like forbiddenHostChars in url.js omits NULL even though it includes tab, lf, cr, space, etc. from the list above. It also skips checking on IPv6 hostnames. These seems like bugs that should be fixed. PR coming soon....
Activity
RaisinTen commentedon Jul 31, 2021
url.parse()has a legacy status: https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehostWhy not just use the WHATWG URL API? It already classifies both urls as invalid ones.
targos commentedon Aug 9, 2021
@nodejs/url
Trott commentedon Mar 8, 2022
The second bug described here, where
new URL('a\0b')reports the input as'a'in the error message, originates in the C++ code. The null character gets treated as the end-of-string marker, but only in the error path. It gets encoded and handled correctly, for example, innew URL('http://example.com/a\0b'). (Safari and Firefox also handle that last one correctly, but Chrome throws. I believe Chrome is deviating from the spec, but even if I'm wrong about that, for the purposes of this conversation, it doesn't matter.)Possible solutions:
std::stringinstead ofchar *and then be very careful so we can preserve the NULL. (I suppose this approach might not work depending on the nature of how the string is handled elsewhere in the C++ code.)TimothyGu commentedon Mar 8, 2022
Chrome's behavior is indeed counter to the spec. https://crbug.com/1099721
Trott commentedon Mar 9, 2022
This is the approach used in #42263.
url: preserve null char in WHATWG URL errors
Trott commentedon Mar 11, 2022
The WHATWG URL error message issue has been fixed. The legacy
url.parse()has several possible solutions. I think the best is to bail on parsing when there is a NULL character (and possibly other C0 characters) in the host (and possibly a few other places?) and return an object with onlypath/pathname/hrefvalues set to anything other thannull.Trott commentedon Mar 11, 2022
https://url.spec.whatwg.org/#host-miscellaneous
Trott commentedon Mar 12, 2022
Looks like
forbiddenHostCharsinurl.jsomitsNULLeven though it includes tab, lf, cr, space, etc. from the list above. It also skips checking on IPv6 hostnames. These seems like bugs that should be fixed. PR coming soon....Trott commentedon Mar 12, 2022
#42313
url: throw on NULL in IPv6 hostname
url: throw on NULL in IPv6 hostname
url: preserve null char in WHATWG URL errors
url: preserve null char in WHATWG URL errors
url: preserve null char in WHATWG URL errors
url: preserve null char in WHATWG URL errors
url: throw on NULL in IPv6 hostname