Merge pull request #311 from github/nickrolfe/oj

Consider Oj.load a sink for unsafe deserialization
This commit is contained in:
Nick Rolfe
2021-10-12 16:17:08 +01:00
committed by GitHub
13 changed files with 269 additions and 76 deletions

View File

@@ -1,24 +0,0 @@
edges
| UnsafeDeserialization.rb:8:39:8:44 | call to params : | UnsafeDeserialization.rb:9:27:9:41 | serialized_data |
| UnsafeDeserialization.rb:14:39:14:44 | call to params : | UnsafeDeserialization.rb:15:30:15:44 | serialized_data |
| UnsafeDeserialization.rb:20:17:20:22 | call to params : | UnsafeDeserialization.rb:21:24:21:32 | json_data |
| UnsafeDeserialization.rb:26:17:26:22 | call to params : | UnsafeDeserialization.rb:27:27:27:35 | json_data |
| UnsafeDeserialization.rb:38:17:38:22 | call to params : | UnsafeDeserialization.rb:39:24:39:32 | yaml_data |
nodes
| UnsafeDeserialization.rb:8:39:8:44 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:9:27:9:41 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:14:39:14:44 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:15:30:15:44 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:20:17:20:22 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:21:24:21:32 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:26:17:26:22 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:27:27:27:35 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:38:17:38:22 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:39:24:39:32 | yaml_data | semmle.label | yaml_data |
subpaths
#select
| UnsafeDeserialization.rb:9:27:9:41 | serialized_data | UnsafeDeserialization.rb:8:39:8:44 | call to params : | UnsafeDeserialization.rb:9:27:9:41 | serialized_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:8:39:8:44 | call to params | user input |
| UnsafeDeserialization.rb:15:30:15:44 | serialized_data | UnsafeDeserialization.rb:14:39:14:44 | call to params : | UnsafeDeserialization.rb:15:30:15:44 | serialized_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:14:39:14:44 | call to params | user input |
| UnsafeDeserialization.rb:21:24:21:32 | json_data | UnsafeDeserialization.rb:20:17:20:22 | call to params : | UnsafeDeserialization.rb:21:24:21:32 | json_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:20:17:20:22 | call to params | user input |
| UnsafeDeserialization.rb:27:27:27:35 | json_data | UnsafeDeserialization.rb:26:17:26:22 | call to params : | UnsafeDeserialization.rb:27:27:27:35 | json_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:26:17:26:22 | call to params | user input |
| UnsafeDeserialization.rb:39:24:39:32 | yaml_data | UnsafeDeserialization.rb:38:17:38:22 | call to params : | UnsafeDeserialization.rb:39:24:39:32 | yaml_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:38:17:38:22 | call to params | user input |

View File

@@ -1,47 +0,0 @@
require "base64"
require "json"
require "yaml"
class UsersController < ActionController::Base
# BAD
def route0
serialized_data = Base64.decode64 params[:key]
object = Marshal.load serialized_data
end
# BAD
def route1
serialized_data = Base64.decode64 params[:key]
object = Marshal.restore serialized_data
end
# BAD
def route2
json_data = params[:key]
object = JSON.load json_data
end
# BAD
def route3
json_data = params[:key]
object = JSON.restore json_data
end
# GOOD - JSON.parse is safe to use on untrusted data
def route4
json_data = params[:key]
object = JSON.parse json_data
end
# BAD
def route5
yaml_data = params[:key]
object = YAML.load yaml_data
end
# GOOD
def route6
yaml_data = params[:key]
object = YAML.safe_load yaml_data
end
end

View File

@@ -0,0 +1,16 @@
require "oj"
class UsersController < ActionController::Base
# GOOD - Oj.load is safe when any mode other than :object is set globally
def route0
json_data = params[:key]
object = Oj.load json_data
end
# BAD - the safe mode set globally is overridden with an unsafe mode passed as
# a call argument
def route1
json_data = params[:key]
object = Oj.load json_data, mode: :object
end
end

View File

@@ -0,0 +1,5 @@
require "oj"
# Set the default mode for the Oj library to use the :compat mode, which makes
# Oj.load safe for untrusted data.
Oj.default_options = { :mode => :compat }

View File

@@ -0,0 +1,8 @@
edges
| OjGlobalOptions.rb:13:17:13:22 | call to params : | OjGlobalOptions.rb:14:22:14:30 | json_data |
nodes
| OjGlobalOptions.rb:13:17:13:22 | call to params : | semmle.label | call to params : |
| OjGlobalOptions.rb:14:22:14:30 | json_data | semmle.label | json_data |
subpaths
#select
| OjGlobalOptions.rb:14:22:14:30 | json_data | OjGlobalOptions.rb:13:17:13:22 | call to params : | OjGlobalOptions.rb:14:22:14:30 | json_data | Unsafe deserialization of $@. | OjGlobalOptions.rb:13:17:13:22 | call to params | user input |

View File

@@ -0,0 +1,35 @@
edges
| UnsafeDeserialization.rb:9:39:9:44 | call to params : | UnsafeDeserialization.rb:10:27:10:41 | serialized_data |
| UnsafeDeserialization.rb:15:39:15:44 | call to params : | UnsafeDeserialization.rb:16:30:16:44 | serialized_data |
| UnsafeDeserialization.rb:21:17:21:22 | call to params : | UnsafeDeserialization.rb:22:24:22:32 | json_data |
| UnsafeDeserialization.rb:27:17:27:22 | call to params : | UnsafeDeserialization.rb:28:27:28:35 | json_data |
| UnsafeDeserialization.rb:39:17:39:22 | call to params : | UnsafeDeserialization.rb:40:24:40:32 | yaml_data |
| UnsafeDeserialization.rb:51:17:51:22 | call to params : | UnsafeDeserialization.rb:52:22:52:30 | json_data |
| UnsafeDeserialization.rb:51:17:51:22 | call to params : | UnsafeDeserialization.rb:53:22:53:30 | json_data |
| UnsafeDeserialization.rb:58:17:58:22 | call to params : | UnsafeDeserialization.rb:68:23:68:31 | json_data |
nodes
| UnsafeDeserialization.rb:9:39:9:44 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:10:27:10:41 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:15:39:15:44 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:16:30:16:44 | serialized_data | semmle.label | serialized_data |
| UnsafeDeserialization.rb:21:17:21:22 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:22:24:22:32 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:27:17:27:22 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:28:27:28:35 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:39:17:39:22 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:40:24:40:32 | yaml_data | semmle.label | yaml_data |
| UnsafeDeserialization.rb:51:17:51:22 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:52:22:52:30 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:53:22:53:30 | json_data | semmle.label | json_data |
| UnsafeDeserialization.rb:58:17:58:22 | call to params : | semmle.label | call to params : |
| UnsafeDeserialization.rb:68:23:68:31 | json_data | semmle.label | json_data |
subpaths
#select
| UnsafeDeserialization.rb:10:27:10:41 | serialized_data | UnsafeDeserialization.rb:9:39:9:44 | call to params : | UnsafeDeserialization.rb:10:27:10:41 | serialized_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:9:39:9:44 | call to params | user input |
| UnsafeDeserialization.rb:16:30:16:44 | serialized_data | UnsafeDeserialization.rb:15:39:15:44 | call to params : | UnsafeDeserialization.rb:16:30:16:44 | serialized_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:15:39:15:44 | call to params | user input |
| UnsafeDeserialization.rb:22:24:22:32 | json_data | UnsafeDeserialization.rb:21:17:21:22 | call to params : | UnsafeDeserialization.rb:22:24:22:32 | json_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:21:17:21:22 | call to params | user input |
| UnsafeDeserialization.rb:28:27:28:35 | json_data | UnsafeDeserialization.rb:27:17:27:22 | call to params : | UnsafeDeserialization.rb:28:27:28:35 | json_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:27:17:27:22 | call to params | user input |
| UnsafeDeserialization.rb:40:24:40:32 | yaml_data | UnsafeDeserialization.rb:39:17:39:22 | call to params : | UnsafeDeserialization.rb:40:24:40:32 | yaml_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:39:17:39:22 | call to params | user input |
| UnsafeDeserialization.rb:52:22:52:30 | json_data | UnsafeDeserialization.rb:51:17:51:22 | call to params : | UnsafeDeserialization.rb:52:22:52:30 | json_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:51:17:51:22 | call to params | user input |
| UnsafeDeserialization.rb:53:22:53:30 | json_data | UnsafeDeserialization.rb:51:17:51:22 | call to params : | UnsafeDeserialization.rb:53:22:53:30 | json_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:51:17:51:22 | call to params | user input |
| UnsafeDeserialization.rb:68:23:68:31 | json_data | UnsafeDeserialization.rb:58:17:58:22 | call to params : | UnsafeDeserialization.rb:68:23:68:31 | json_data | Unsafe deserialization of $@. | UnsafeDeserialization.rb:58:17:58:22 | call to params | user input |

View File

@@ -0,0 +1 @@
queries/security/cwe-502/UnsafeDeserialization.ql

View File

@@ -0,0 +1,76 @@
require "base64"
require "json"
require "oj"
require "yaml"
class UsersController < ActionController::Base
# BAD
def route0
serialized_data = Base64.decode64 params[:key]
object = Marshal.load serialized_data
end
# BAD
def route1
serialized_data = Base64.decode64 params[:key]
object = Marshal.restore serialized_data
end
# BAD
def route2
json_data = params[:key]
object = JSON.load json_data
end
# BAD
def route3
json_data = params[:key]
object = JSON.restore json_data
end
# GOOD - JSON.parse is safe to use on untrusted data
def route4
json_data = params[:key]
object = JSON.parse json_data
end
# BAD
def route5
yaml_data = params[:key]
object = YAML.load yaml_data
end
# GOOD
def route6
yaml_data = params[:key]
object = YAML.safe_load yaml_data
end
# BAD - Oj.load is unsafe in its default :object mode
def route7
json_data = params[:key]
object = Oj.load json_data
object = Oj.load json_data, mode: :object
end
# GOOD - Oj.load is safe in any other mode
def route8
json_data = params[:key]
# Test the different ways the options hash can be passed
options = { allow_blank: true, mode: :rails }
object1 = Oj.load json_data, options
object2 = Oj.load json_data, mode: :strict
object3 = Oj.load json_data, :allow_blank => true, :mode => :compat
# TODO: false positive; we aren't detecting flow from `:json` to the call argument.
more_options = { allow_blank: true }
more_options[:mode] = :json
object4 = Oj.load json_data, more_options
end
# GOOD
def route9
json_data = params[:key]
object = Oj.safe_load json_data
end
end