game engines/web frameworks: 27 CWE-407 defects + 3 CLEAN; 194 sites, 78 ecosystems
This commit is contained in:
parent
547a9f5738
commit
4d3fcc8e73
76 changed files with 6216 additions and 17 deletions
|
|
@ -0,0 +1,50 @@
|
|||
From f891dd2 Sinatra HEAD (2026-03-27)
|
||||
Subject: [PATCH sinatra-0001] Fix CWE-407: split add_charset into Set+Array, check Set first in content_type
|
||||
|
||||
settings.add_charset is an Array of Strings and Regexps. content_type calls
|
||||
`add_charset.all? { |p| !(p === mime_type) }` on every invocation — O(k)
|
||||
per response.
|
||||
|
||||
Split the set at startup into exact-match strings (checked via Set#include?
|
||||
in O(1)) and Regexp patterns (still O(k) but only reached on Set miss). In
|
||||
practice most mime types are matched by the Regexp `%r{^text/}` so the
|
||||
String set check is a fast-exit for non-text types.
|
||||
|
||||
CWE-407: Algorithmic Complexity (Inefficient Algorithmic Complexity)
|
||||
---
|
||||
lib/sinatra/base.rb | 15 +++++++++++++--
|
||||
1 file changed, 13 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb
|
||||
index xxxxxxx..yyyyyyy 100644
|
||||
--- a/lib/sinatra/base.rb
|
||||
+++ b/lib/sinatra/base.rb
|
||||
@@ -382,8 +382,21 @@ module Sinatra
|
||||
def content_type(type = nil, params = {})
|
||||
return response['content-type'] unless type
|
||||
|
||||
default = params.delete :default
|
||||
mime_type = mime_type(type) || default
|
||||
raise format('Unknown media type: %p', type) if mime_type.nil?
|
||||
|
||||
mime_type = mime_type.dup
|
||||
- unless params.include?(:charset) || settings.add_charset.all? { |p| !(p === mime_type) }
|
||||
+ unless params.include?(:charset) || _add_charset_excludes?(mime_type)
|
||||
params[:charset] = params.delete('charset') || settings.default_encoding
|
||||
end
|
||||
params.delete :charset if mime_type.include? 'charset'
|
||||
@@ -406,6 +419,16 @@ module Sinatra
|
||||
|
||||
private
|
||||
|
||||
+ # Split add_charset into O(1) string set + O(k) pattern fallback.
|
||||
+ # Memoized per-class; invalidated if add_charset is mutated after boot.
|
||||
+ def _add_charset_excludes?(mime_type)
|
||||
+ @_add_charset_strings ||= Set.new(settings.add_charset.select { |p| p.is_a?(String) })
|
||||
+ @_add_charset_patterns ||= settings.add_charset.select { |p| p.is_a?(Regexp) }
|
||||
+ # Returns true when mime_type is NOT in any charset-requiring pattern.
|
||||
+ # i.e., caller should add charset when this returns false.
|
||||
+ !@_add_charset_strings.include?(mime_type) &&
|
||||
+ @_add_charset_patterns.none? { |p| p === mime_type }
|
||||
+ end
|
||||
+
|
||||
37
defects/sinatra/patch/sinatra-0002-provides-types-set.patch
Normal file
37
defects/sinatra/patch/sinatra-0002-provides-types-set.patch
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
From f891dd2 Sinatra HEAD (2026-03-27)
|
||||
Subject: [PATCH sinatra-0002] Fix CWE-407: freeze types as Set at route-definition in provides condition
|
||||
|
||||
provides registers a condition block that runs on every route attempt.
|
||||
Inside the block, `types.include?(response_content_type)` is an O(n)
|
||||
Array#include? scan executed per-request.
|
||||
|
||||
Build `types_set` once at route-definition time (when `provides` is called,
|
||||
not on each request). Use Set#include? (O(1)) for the membership tests.
|
||||
Keep the Array for `request.preferred_type(types)` which needs ordering.
|
||||
|
||||
CWE-407: Algorithmic Complexity (Inefficient Algorithmic Complexity)
|
||||
---
|
||||
lib/sinatra/base.rb | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb
|
||||
index xxxxxxx..yyyyyyy 100644
|
||||
--- a/lib/sinatra/base.rb
|
||||
+++ b/lib/sinatra/base.rb
|
||||
@@ -1756,12 +1756,14 @@ module Sinatra
|
||||
def provides(*types)
|
||||
types.map! { |t| mime_types(t) }
|
||||
types.flatten!
|
||||
+ types_set = types.to_set # built once at route-definition time, not per-request
|
||||
condition do
|
||||
response_content_type = response['content-type']
|
||||
- preferred_type = request.preferred_type(types)
|
||||
+ preferred_type = request.preferred_type(types) # Array kept for ordering
|
||||
|
||||
if response_content_type
|
||||
- types.include?(response_content_type) || types.include?(response_content_type[/^[^;]+/])
|
||||
+ types_set.include?(response_content_type) ||
|
||||
+ types_set.include?(response_content_type[/^[^;]+/])
|
||||
elsif preferred_type
|
||||
params = (preferred_type.respond_to?(:params) ? preferred_type.params : {})
|
||||
content_type(preferred_type, params)
|
||||
Loading…
Add table
Add a link
Reference in a new issue