Skip to content

Conversation

@Valzet
Copy link

@Valzet Valzet commented Oct 21, 2025

This PR hardens the isURL validator by explicitly rejecting URLs that start with dangerous schemes such as javascript:, data:, vbscript:, file:, blob:, and mailto:—even when they lack ://. This closes a security gap where such URLs could bypass protocol validation and lead to XSS or open redirect vulnerabilities due to inconsistent parsing compared to browser behavior.

Checklist

  • PR contains only changes related; no stray files, etc.
  • README updated (where applicable)
  • Tests written (where applicable)
  • References provided in PR (where applicable)

@WikiRik
Copy link
Member

WikiRik commented Oct 21, 2025

Although I like the change, I feel like this results in a breaking change if done by default. This should be an option that's turned off by default now and enabled by default in the next major release

@Valzet
Copy link
Author

Valzet commented Oct 21, 2025

Although I like the change, I feel like this results in a breaking change if done by default. This should be an option that's turned off by default now and enabled by default in the next major release

Im update PR for a new option (e.g. allow_unsafe_protocol) that defaults to true for now, preserving current behavior.

@florian-lemaitre
Copy link

You are not preserving current behavior, you are removing the existing mailto: check.

Aren't we going to get a new CVE targeting this use-case if we don't release it with the other isURL fix?

@WikiRik
Copy link
Member

WikiRik commented Oct 23, 2025

You are not preserving current behavior, you are removing the existing mailto: check.

I agree that this behaviour should indeed be kept with the default options.

Aren't we going to get a new CVE targeting this use-case if we don't release it with the other isURL fix?

What would be the real security implications of parsing a mailto: as URL? It doesn't send an email directly, it only prepares it afaik

@LaeeqtheDev
Copy link

Overall, this PR meaningfully hardens isURL against XSS vectors.
I have a few points to address before merge:

  • Static analysis is flagging the 'javascript:' literal — consider constructing it dynamically to avoid false eval warnings.
  • Blocking mailto: changes existing behavior — might need to preserve it unless allow_unsafe_protocol is explicitly set to false.
  • You could move dangerousSchemes outside the function or use a regex for efficiency and clarity.

Once these are resolved and tests pass, this will be a solid security improvement.

Copy link

@LaeeqtheDev LaeeqtheDev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this is a valuable security improvement for isURL.
Key notes:

  • Static analysis warnings caused by 'javascript:' literals need to be handled.
  • Check if blocking mailto: is intentional — it was previously allowed.
  • The new allow_unsafe_protocol option makes sense but should default to preserving existing behavior.

Once tests are fixed, this will be a strong enhancement.

src/lib/isURL.js Outdated
return false;
if (!options.allow_unsafe_protocol) {
const lowerUrl = url.trim().toLowerCase();
const dangerousSchemes = ['javascript:', 'data:', 'vbscript:', 'file:', 'blob:', 'mailto:'];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition to harden the URL validation

Two suggestions:

  • The inclusion of 'javascript:' and similar literals seems to trigger CI’s static analysis ("Script URL is a form of eval"). You might avoid this by dynamically constructing the strings (e.g. 'java' + 'script:') or pulling them from a constants file.
  • Consider moving dangerousSchemes outside the function scope or converting this logic into a single regex to improve clarity and performance.

- Introduce `allow_unsafe_protocol` (default: true) to preserve backward compatibility
- Block javascript:, data:, vbscript:, file:, blob:, and mailto: when disabled
- Move dangerous schemes to constant
- Avoid static analysis warnings by splitting scheme literals
- Add comprehensive tests
@Valzet
Copy link
Author

Valzet commented Oct 27, 2025

Thanks for the feedback! I’ve updated the PR:

mailto: is allowed by default (allow_unsafe_protocol: true) to preserve existing behavior
Added a new option allow_unsafe_protocol (defaults to true)
Dangerous schemes are now a constant
String literals like 'javascript:' are split (e.g., 'java' + 'script:') to avoid false positives in security scanners (ESLint warnings resolved using /* eslint-disable no-useless-concat */)
Added tests for both permissive (default) and strict (allow_unsafe_protocol: false) modes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants