Skip to content

Instantly share code, notes, and snippets.

@tacone
Created February 18, 2022 20:41
Show Gist options
  • Save tacone/ace20190793a6bad667430bbd644e446 to your computer and use it in GitHub Desktop.
Save tacone/ace20190793a6bad667430bbd644e446 to your computer and use it in GitHub Desktop.
Make sure a Url is safe to call from your service
import hostnameIsPrivate from "hostname-is-private";
import { promisify } from "util";
const isSafeUrl = async (untrustedUrl, protocols = ["http", "https"]) => {
try {
// will throw error on malfomed url
const url = new URL(untrustedUrl);
// no protocol, no fun
if (!url.protocol) return false;
// make sure the protocol is allowed, no file://, ftp:// etc
if (
!protocols.filter(
(p) => `${p.toLowerCase()}:` == url.protocol.toLowerCase()
).length
) {
return false;
}
// here it gets interesting, we need to check if the hostname exists,
// is reachable, and is not private. We need especially to be sure it
// won't resolve to localhost :-))
const notAllowed = await promisify(
hostnameIsPrivate.isPrivateIncludingPublicIp
)(url.hostname);
if (notAllowed) {
throw new Error(`Url "${url.hostname} is not allowed`);
}
return true;
} catch (err) {
console.error(err);
return false;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment