Skip to content

Commit f4d8a68

Browse files
authored
fix(ShadyURL): ignore valid URL with unknown protocol (#436)
1 parent 30f9afe commit f4d8a68

File tree

4 files changed

+63
-0
lines changed

4 files changed

+63
-0
lines changed

.changeset/vast-emus-reply.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nodesecure/js-x-ray": patch
3+
---
4+
5+
Ignore valid URL with unknown protocol

workspaces/js-x-ray/src/ShadyURL.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,39 @@ const kShadyLinkRegExps = [
77
/(http[s]?:\/\/.*\.(link|xyz|tk|ml|ga|cf|gq|pw|top|club|mw|bd|ke|am|sbs|date|quest|cd|bid|ws|icu|cam|uno|email|stream))$/
88
];
99

10+
// List of known URI schemes (IANA registered + common ones)
11+
// See: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml
12+
const kKnownProtocols = new Set([
13+
// Web
14+
"http:", "https:",
15+
// File & Data
16+
"file:", "data:", "blob:",
17+
// FTP
18+
"ftp:", "ftps:", "sftp:", "tftp:",
19+
// Mail & Messaging
20+
"mailto:", "xmpp:", "irc:", "ircs:", "sip:", "sips:", "tel:", "sms:", "mms:",
21+
// Remote access
22+
"ssh:", "telnet:", "vnc:", "rdp:",
23+
// Version control
24+
"git:", "svn:", "cvs:", "hg:",
25+
// P2P & Torrents
26+
"magnet:", "ed2k:", "torrent:",
27+
// Crypto & Blockchain
28+
"bitcoin:", "ethereum:", "ipfs:", "ipns:",
29+
// App-specific
30+
"slack:", "discord:", "spotify:", "steam:", "skype:", "zoommtg:", "msteams:",
31+
"vscode:", "vscode-insiders:", "jetbrains:",
32+
// Mobile & Desktop deep links
33+
"intent:", "market:", "itms:", "itms-apps:", "fb:", "twitter:", "instagram:", "whatsapp:", "tg:",
34+
// Other common protocols
35+
"ws:", "wss:", "ldap:", "ldaps:", "nntp:", "news:", "rtsp:", "rtspu:", "rtsps:",
36+
"webcal:", "feed:", "podcast:",
37+
// eslint-disable-next-line no-script-url
38+
"javascript:", "about:", "view-source:",
39+
// Security related
40+
"acap:", "cap:", "cid:", "mid:", "urn:", "tag:", "dns:", "geo:", "ni:", "nih:"
41+
]);
42+
1043
export class ShadyURL {
1144
static isSafe(
1245
input: string
@@ -16,6 +49,11 @@ export class ShadyURL {
1649
}
1750

1851
const parsedUrl = new URL(input);
52+
// Unknown protocol, not a real URL
53+
if (!kKnownProtocols.has(parsedUrl.protocol)) {
54+
return true;
55+
}
56+
1957
const hostname = parsedUrl.hostname;
2058
if (ipaddress.isValid(hostname)) {
2159
if (this.#isPrivateIPAddress(hostname)) {

workspaces/js-x-ray/test/ShadyURL.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ describe("ShadyURL.isSafe()", () => {
1515
assert.equal(ShadyURL.isSafe(""), true);
1616
});
1717

18+
it("should return true for a valid URL but with unknown protocol", () => {
19+
assert.equal(ShadyURL.isSafe("unknown://example.com"), true);
20+
});
21+
1822
it("should return true for a malformed URL", () => {
1923
assert.equal(ShadyURL.isSafe("http://"), true);
2024
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Import Node.js Dependencies
2+
import { test } from "node:test";
3+
import assert from "node:assert/strict";
4+
5+
// Import Internal Dependencies
6+
import { AstAnalyser } from "../../src/index.js";
7+
8+
// Regression test for https://github.com/NodeSecure/js-x-ray/issues/434
9+
test("it should not return shady-link warning", () => {
10+
const { warnings } = new AstAnalyser().analyse(`
11+
var debug = require('debug')('express:view');
12+
`);
13+
14+
assert.strictEqual(warnings.length, 0);
15+
});
16+

0 commit comments

Comments
 (0)