Deserialization of user-controlled data¶
ID: rb/unsafe-deserializationKind: path-problemSecurity severity: 9.8Severity: warningPrecision: highTags: - security - external/cwe/cwe-502Query suites: - ruby-code-scanning.qls - ruby-security-extended.qls - ruby-security-and-quality.qls
Click to see the query in the CodeQL repository
Deserializing untrusted data using any method that allows the construction of arbitrary objects is easily exploitable and, in many cases, allows an attacker to execute arbitrary code.
Recommendation¶
Avoid deserialization of untrusted data if possible. If the architecture permits it, use serialization formats that cannot represent arbitrary objects. For libraries that support it, such as the Ruby standard library’sJSON module, ensure that the parser is configured to disable deserialization of arbitrary objects.
If deserializing an untrusted YAML document using thepsych gem, prefer thesafe_load andsafe_load_file methods overload andload_file, as the former will safely handle untrusted data. Avoid passing untrusted data to theload_stream method. Inpsych version 4.0.0 and above, theload method can safely be used.
If deserializing an untrusted XML document using theox gem, do not useparse_obj andload using the non-default :object mode. Instead use theload method in the default mode or better explicitly set a safe mode such as :hash.
To safely deserializeProperty List files using theplist gem, ensure that you passmarshal:false when callingPlist.parse_xml.
Example¶
The following example calls theMarshal.load,JSON.load,YAML.load,Oj.load andOx.parse_obj methods on data from an HTTP request. Since these methods are capable of deserializing to arbitrary objects, this is inherently unsafe.
require'json'require'yaml'require'oj'classUserController<ActionController::Basedefmarshal_exampledata=Base64.decode64params[:data]object=Marshal.loaddata# ...enddefjson_exampleobject=JSON.loadparams[:json]# ...enddefyaml_exampleobject=YAML.loadparams[:yaml]# ...enddefoj_exampleobject=Oj.loadparams[:json]# ...enddefox_exampleobject=Ox.parse_objparams[:xml]# ...endend
UsingJSON.parse andYAML.safe_load instead, as in the following example, removes the vulnerability. Similarly, callingOj.load with any mode other than:object is safe, as is callingOj.safe_load. Note that there is no safe way to deserialize untrusted data usingMarshal.
require'json'classUserController<ActionController::Basedefsafe_json_exampleobject=JSON.parseparams[:json]# ...enddefsafe_yaml_exampleobject=YAML.safe_loadparams[:yaml]# ...enddefsafe_oj_exampleobject=Oj.loadparams[:yaml],{mode::strict}# orobject=Oj.safe_loadparams[:yaml]# ...endend
References¶
OWASP vulnerability description:deserialization of untrusted data.
Ruby documentation:guidance on deserializing objects safely.
Ruby documentation:security guidance on the Marshal library.
Ruby documentation:security guidance on JSON.load.
Ruby documentation:security guidance on the YAML library.
You can read that how unsafe yaml load methods can lead to code executions:Universal Deserialisation Gadget for Ruby 2.x-3.x.
Common Weakness Enumeration:CWE-502.