@@ -90,12 +90,32 @@ def self.valid?(payload:, headers:, secret:, config:)
9090 return false if secret . nil? || secret . empty?
9191
9292 validator_config = build_config ( config )
93- normalized_headers = normalize_headers ( headers )
9493
95- # Get signature from headers
94+ # Security: Check raw headers BEFORE normalization to detect tampering
95+ return false unless headers . respond_to? ( :each )
96+
9697 signature_header = validator_config [ :header ]
98+
99+ # Find the signature header with case-insensitive matching but preserve original value
100+ raw_signature = nil
101+ headers . each do |key , value |
102+ if key . to_s . downcase == signature_header . downcase
103+ raw_signature = value . to_s
104+ break
105+ end
106+ end
107+
108+ return false if raw_signature . nil? || raw_signature . empty?
109+
110+ # Security: Reject signatures with leading/trailing whitespace
111+ return false if raw_signature != raw_signature . strip
112+
113+ # Security: Reject signatures containing null bytes or other control characters
114+ return false if raw_signature . match? ( /[\u0000 -\u001f \u007f -\u009f ]/ )
115+
116+ # Now we can safely normalize headers for the rest of the validation
117+ normalized_headers = normalize_headers ( headers )
97118 provided_signature = normalized_headers [ signature_header . downcase ]
98- return false if provided_signature . nil? || provided_signature . empty?
99119
100120 # Validate timestamp if required (for services that include timestamp validation)
101121 if validator_config [ :timestamp_header ]
@@ -178,10 +198,13 @@ def self.valid_timestamp?(headers, config)
178198
179199 return false unless timestamp_value
180200
201+ # Security: Strict timestamp validation - must be only digits with no leading zeros
202+ return false unless timestamp_value . match? ( /\A [1-9]\d *\z / ) || timestamp_value == "0"
203+
181204 timestamp = timestamp_value . to_i
182205
183- # Ensure timestamp is a valid integer
184- return false unless timestamp . is_a? ( Integer ) && timestamp > 0
206+ # Ensure timestamp is a positive integer (reject zero and negative)
207+ return false unless timestamp > 0
185208
186209 current_time = Time . now . to_i
187210 tolerance = config [ :timestamp_tolerance ]
0 commit comments