Skip to content

Commit a2e1fcf

Browse files
committed
Improve the inflate method. Prevent potential DoS vulnerability in Zlib::Inflate by limiting the maximum decompressed size. The data is now inflated in chunks.
1 parent cff9c06 commit a2e1fcf

File tree

1 file changed

+35
-5
lines changed

1 file changed

+35
-5
lines changed

lib/ruby_saml/xml/decoder.rb

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def decode_message(message, max_bytesize = nil)
2323

2424
return message unless base64_encoded?(message)
2525

26-
message = try_inflate(base64_decode(message))
26+
message = try_inflate(base64_decode(message), max_bytesize)
2727

2828
if message.bytesize > max_bytesize # rubocop:disable Style/IfUnlessModifier
2929
raise ValidationError.new("SAML Message exceeds #{max_bytesize} bytes, so was rejected")
@@ -66,18 +66,48 @@ def base64_encoded?(string)
6666

6767
# Attempt inflating a string, if it fails, return the original string.
6868
# @param data [String] The string
69+
# @param max_bytesize [Integer] The maximum allowed size of the SAML Message,
70+
# to prevent a possible DoS attack.
6971
# @return [String] The inflated or original string
70-
def try_inflate(data)
71-
inflate(data)
72+
def try_inflate(data, max_bytesize = nil)
73+
inflate(data, max_bytesize)
7274
rescue Zlib::Error
7375
data
7476
end
7577

7678
# Inflate method.
7779
# @param deflated [String] The string
80+
# @param max_bytesize [Integer] The maximum allowed size of the SAML Message,
81+
# to prevent a possible DoS attack.
7882
# @return [String] The inflated string
79-
def inflate(deflated)
80-
Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(deflated)
83+
def inflate(deflated, max_bytesize = nil)
84+
unless max_bytesize.nil?
85+
inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
86+
87+
# Use a StringIO buffer to build the inflated message incrementally.
88+
buffer = StringIO.new
89+
90+
inflater.inflate(deflated) do |chunk|
91+
if buffer.length + chunk.bytesize > max_bytesize
92+
inflater.close
93+
raise ValidationError, "SAML Message exceeds #{max_bytesize} bytes during decompression, so was rejected"
94+
end
95+
buffer << chunk
96+
end
97+
98+
final_chunk = inflater.finish
99+
unless final_chunk.empty?
100+
if buffer.length + final_chunk.bytesize > max_bytesize
101+
raise ValidationError, "SAML Message exceeds #{max_bytesize} bytes during decompression, so was rejected"
102+
end
103+
buffer << final_chunk
104+
end
105+
106+
inflater.close
107+
buffer.string
108+
else
109+
Zlib::Inflate.new(-Zlib::MAX_WBITS).inflate(deflated)
110+
end
81111
end
82112

83113
# Deflate method.

0 commit comments

Comments
 (0)