diff --git a/Gemfile b/Gemfile
index 1ee4468077436f4c0695ba4fb89ceb2cc1112458..5758b1b554e1a74fab9ac396b1960cae43a71de1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -164,7 +164,7 @@ gem 'rainbow', '~> 2.2'
 gem 'settingslogic', '~> 2.0.9'
 
 # Linear-time regex library for untrusted regular expressions
-gem 're2', '~> 1.0.0'
+gem 're2', '~> 1.1.0'
 
 # Misc
 
diff --git a/Gemfile.lock b/Gemfile.lock
index b0b437ae3422f0a2635108c47ff69610bd7c79db..f8aaba57998d12099a0c9b56dc4695119453bcaa 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -656,7 +656,7 @@ GEM
       debugger-ruby_core_source (~> 1.3)
     rdoc (4.2.2)
       json (~> 1.4)
-    re2 (1.0.0)
+    re2 (1.1.0)
     recaptcha (3.0.0)
       json
     recursive-open-struct (1.0.0)
@@ -1055,7 +1055,7 @@ DEPENDENCIES
   raindrops (~> 0.18)
   rblineprof (~> 0.3.6)
   rdoc (~> 4.2)
-  re2 (~> 1.0.0)
+  re2 (~> 1.1.0)
   recaptcha (~> 3.0)
   redcarpet (~> 3.4)
   redis (~> 3.2)
diff --git a/lib/gitlab/untrusted_regexp.rb b/lib/gitlab/untrusted_regexp.rb
index 187a9e1145fb1636f80bbc1cce903dc4a61d1d10..7ce2e9d636e6b3353aa01a2849208e3fda069406 100644
--- a/lib/gitlab/untrusted_regexp.rb
+++ b/lib/gitlab/untrusted_regexp.rb
@@ -22,33 +22,9 @@ module Gitlab
     end
 
     def scan(text)
-      text = text.dup # modified in-place
-      results = []
-
-      loop do
-        match = scan_regexp.match(text)
-        break unless match
-
-        # Ruby scan returns empty strings, not nil
-        groups = match.to_a.map(&:to_s)
-
-        results << 
-          if regexp.number_of_capturing_groups.zero?
-            groups[0]
-          else
-            groups[1..-1]
-          end
-
-        matchsize = match.end(0)
-
-        # No further matches
-        break unless matchsize.present?
-
-        text.slice!(0, matchsize)
-        break unless text.present?
-      end
-
-      results
+      matches = scan_regexp.scan(text).to_a
+      matches.map!(&:first) if regexp.number_of_capturing_groups.zero?
+      matches
     end
 
     def replace(text, rewrite)
diff --git a/spec/lib/gitlab/ci/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb
index 8b925fd4e22dd9d7ac8bd5b8aa28dbed570ec738..ebe5af561601ddcd50a0528cc102d1a786047b68 100644
--- a/spec/lib/gitlab/ci/trace/stream_spec.rb
+++ b/spec/lib/gitlab/ci/trace/stream_spec.rb
@@ -308,6 +308,20 @@ describe Gitlab::Ci::Trace::Stream do
       it { is_expected.to eq('65') }
     end
 
+    context 'long line' do
+      let(:data) { 'a' * 80000 + '100%' + 'a' * 80000 }
+      let(:regex) { '\d+\%' }
+
+      it { is_expected.to eq('100') }
+    end
+
+    context 'many lines' do
+      let(:data) { "foo\n" * 80000 + "100%\n" + "foo\n" * 80000 }
+      let(:regex) { '\d+\%' }
+
+      it { is_expected.to eq('100') }
+    end
+
     context 'empty regex' do
       let(:data) { 'foo' }
       let(:regex) { '' }
diff --git a/spec/lib/gitlab/untrusted_regexp_spec.rb b/spec/lib/gitlab/untrusted_regexp_spec.rb
index 21d47b7897a6776ea503000ffa48f17b4268acb4..bed58d407ef6bb721ad0fc2cb50315b68fe34899 100644
--- a/spec/lib/gitlab/untrusted_regexp_spec.rb
+++ b/spec/lib/gitlab/untrusted_regexp_spec.rb
@@ -54,8 +54,8 @@ describe Gitlab::UntrustedRegexp do
       let(:regexp) { '' }
       let(:text) { 'foo' }
 
-      it 'returns an array of empty matches' do
-        is_expected.to eq([''])
+      it 'returns an array of nil matches' do
+        is_expected.to eq([nil, nil, nil, nil])
       end
     end
 
@@ -63,8 +63,8 @@ describe Gitlab::UntrustedRegexp do
       let(:regexp) { '()' }
       let(:text) { 'foo' }
 
-      it 'returns an array of empty matches in an array' do
-        is_expected.to eq([['']])
+      it 'returns an array of nil matches in an array' do
+        is_expected.to eq([[nil], [nil], [nil], [nil]])
       end
     end