Multiple Cross Site Scripting Vulnerabilities

Base Metricscoreseverity
overall9critical

Type: Vulnerability

Status: fixed

Reporting Date: 2023.04.10

Due to usage of dangerouslySetInnerHTML in the client it is possible to execute arbitrary javascript in the application context. This requires a malicious README.md in one of the synced repositories.

Description

The frontend client has several instances of dangerouslySetInnerHTML, which bypasses the shadow DOM of React and allows the input to be directly rendered. If the input is controlled by the user without further sanitization cross site scripting attacks are possible.

The most impactful component using the dangerouslySetInnerHTML function is the README.md preview of a synced repository.

After opening a malicious repository, the arbitrary HTML content is rendered and executed. This is a stored XSS1.

client/src/pages/Repository/RepositoryOverview.tsx#L87-L112

</div>
      {readme ? (
        <div>
          <Accordion
            title={'Readme'}
            icon={<FileIcon filename={readme.path} />}
          >
            <div className="py-4 text-xs overflow-x-auto px-4 readme">
              <div
                dangerouslySetInnerHTML={{ __html: readme.contents }}
                onClick={(e) => {
                  // @ts-ignore
                  const { href } = e.target;
                  if (href) {
                    e.preventDefault();
                    openLink(href);
                  }
                }}
              />
            </div>
          </Accordion>
        </div>
      ) : (
        ''
      )}
    </div>

To render the markdown the remarkable2 library with enabled HTML rendering is used. This allows direct rendering of HTML inside the markdown content.

const md = new Remarkable({
  html: true,

Proof of Concept to crash the application:

  • mkdir -p test_repo
  • cd test_repo
  • git init
  • Place the below content into README.md
<input id="path" oninput="window.__TAURI_INVOKE__(`tauri`,{__tauriModule:`Process`,message:{cmd:`exit`,exitCode: 1}}).then(console.log)" type="text"/>
  • git stage README.md && git commit -m "Initial Commit"
  • Sync this repository with bloop
  • Inspect the repository inside bloop and observe the application crashing

The direct rendering is also used in /client/src/components/CodeBlock/SemanticSearch/Answer/index.tsx#L89 and /client/src/pages/NLResults/Message.tsx#L139, where the same proof of concept would work, but the attack vectors are different. The highlightedAnswer from both instances seems to require the user to provide the payload, which could be classified as a self-xss3.

Impact

Due to several unused Tauri APIs exposed it is possible to:

  • Crash the application
  • Trick users into allowing filesystem access
  • Trick users into entering their github credentials
  • Read and exfiltrate all synced repositories
  • Modify all synced repositories
  • Execute all enabled Tauri commands
  • Intercept and exfiltrate all user interaction

Recommendation

This issue can be fixed in multiple ways, depending on the importance of HTML content being rendered.

  • Disable the HTML feature of the markdown renderer

OR

  • Sanitize the input after rendering with libraries like dompurify4

We recommend to disable the HTML input, as the sanitization process is only meant to reduce but not to erase the risk of unwanted HTML to be processed and rendered.

Retest Notes

The issue was fixed in the critical instance by sanitizing the input with sanitize-html in PR 967. The self-XSS instances were not fixed yet but they require user interaction and do not pose immediate risk.