pablo-abc / svelte-markdown

Markdown parser to svelte components
MIT License
360 stars 50 forks source link

Feat Request: disallow javascript protocol by default #66

Closed ShadiestGoat closed 1 year ago

ShadiestGoat commented 1 year ago

If linking using javascript, eg. [click me (trust me)](javascript:alert(JSON.stringify(localStorage))), this should not be parsed as a link by default.

xenorio commented 1 year ago

I don't think this should not work by default. It's a markdown parser, not a sanitizer. Parsing what you're giving it is expected.

However, you can easily do this yourself.

Option 1

Set a custom link renderer that checks for the beginning of the URL and replaces it

<script lang="ts">
  export let href: string;
  export let text: string;

  if(href.toLowerCase().startsWith("javascript:"))href = "#" // You can get creative here!
</script>

<a href={href}>{text}</a>

Option 2

This can be prevented by disabling unsafe-inline script sources via CSP

svelte.config.js:

kit: {
    adapter: adapter(),
    files: {
        lib: 'src/lib'
    },
    csp: {
        mode: 'hash',
        directives: {
            "default-src": ["self", "localhost:*", "data:"]
        }
    }
}

When clicking on your example:

image

ShadiestGoat commented 1 year ago

You are probably right - this is probably out of scope.

For future reference, .startsWith("javascript:") is not good enough for removal of scripts (j a v a s c r i p t:, etc, is also legal)

xenorio commented 1 year ago

j a v a s c r i p t: is in fact not legal.

First of all, it won't be detected as a link and therefore be rendered as plain text

Second of all, even when you manually insert it into the href attribute (inspect element) it will go to http://localhost/j a v a s c r i p t:... and produce a 404

However, if you wanna be extra cautious, you can turn it into a URL object and read its protocol value, which will always stay the same:

<script lang="ts">
  export let href: string;
  export let text: string;

  try {
    let url = new URL(href)

    switch (url.protocol) {
      case "javascript:":
        href = "#"
        break;

      // Insert more protocols here

      default:
        break;
    }

  } catch (error) {
    // Provided URL is invalid
    href = "#"
  }

</script>

<a href={href} target="_blank">{text}</a>