Commit 126fe4c0 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'mermaid-chaining' into 'master'

Prevent DOS from Chaining in Mermaid

See merge request gitlab-org/gitlab!60382
parents 5d89cb72 6bcf37a9
import $ from 'jquery'; import $ from 'jquery';
import { once } from 'lodash'; import { once, countBy } from 'lodash';
import { deprecatedCreateFlash as flash } from '~/flash'; import { deprecatedCreateFlash as flash } from '~/flash';
import { darkModeEnabled } from '~/lib/utils/color_utils'; import { darkModeEnabled } from '~/lib/utils/color_utils';
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
...@@ -22,6 +22,8 @@ import { __, sprintf } from '~/locale'; ...@@ -22,6 +22,8 @@ import { __, sprintf } from '~/locale';
const MAX_CHAR_LIMIT = 2000; const MAX_CHAR_LIMIT = 2000;
// Max # of mermaid blocks that can be rendered in a page. // Max # of mermaid blocks that can be rendered in a page.
const MAX_MERMAID_BLOCK_LIMIT = 50; const MAX_MERMAID_BLOCK_LIMIT = 50;
// Max # of `&` allowed in Chaining of links syntax
const MAX_CHAINING_OF_LINKS_LIMIT = 30;
// Keep a map of mermaid blocks we've already rendered. // Keep a map of mermaid blocks we've already rendered.
const elsProcessingMap = new WeakMap(); const elsProcessingMap = new WeakMap();
let renderedMermaidBlocks = 0; let renderedMermaidBlocks = 0;
...@@ -64,6 +66,18 @@ function importMermaidModule() { ...@@ -64,6 +66,18 @@ function importMermaidModule() {
}); });
} }
function shouldLazyLoadMermaidBlock(source) {
/**
* If source contains `&`, which means that it might
* contain Chaining of links a new syntax in Mermaid.
*/
if (countBy(source)['&'] > MAX_CHAINING_OF_LINKS_LIMIT) {
return true;
}
return false;
}
function fixElementSource(el) { function fixElementSource(el) {
// Mermaid doesn't like `<br />` tags, so collapse all like tags into `<br>`, which is parsed correctly. // Mermaid doesn't like `<br />` tags, so collapse all like tags into `<br>`, which is parsed correctly.
const source = el.textContent.replace(/<br\s*\/>/g, '<br>'); const source = el.textContent.replace(/<br\s*\/>/g, '<br>');
...@@ -128,7 +142,8 @@ function renderMermaids($els) { ...@@ -128,7 +142,8 @@ function renderMermaids($els) {
if ( if (
(source && source.length > MAX_CHAR_LIMIT) || (source && source.length > MAX_CHAR_LIMIT) ||
renderedChars > MAX_CHAR_LIMIT || renderedChars > MAX_CHAR_LIMIT ||
renderedMermaidBlocks >= MAX_MERMAID_BLOCK_LIMIT renderedMermaidBlocks >= MAX_MERMAID_BLOCK_LIMIT ||
shouldLazyLoadMermaidBlock(source)
) { ) {
const html = ` const html = `
<div class="alert gl-alert gl-alert-warning alert-dismissible lazy-render-mermaid-container js-lazy-render-mermaid-container fade show" role="alert"> <div class="alert gl-alert gl-alert-warning alert-dismissible lazy-render-mermaid-container js-lazy-render-mermaid-container fade show" role="alert">
......
---
title: Prevent DOS from Chaining in Mermaid
merge_request: 60382
author:
type: security
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment