1= Ruby Security
2
3The Ruby programming language is large and complex and there are many security
4pitfalls often encountered by newcomers and experienced Rubyists alike.
5
6This document aims to discuss many of these pitfalls and provide more secure
7alternatives where applicable.
8
9Please check the full list of publicly known CVEs and how to correctly report a
10security vulnerability, at: https://www.ruby-lang.org/en/security/
11Japanese version is here: https://www.ruby-lang.org/ja/security/
12
13Security vulnerabilities should be reported via an email to
14mailto:security@ruby-lang.org ({the PGP public
15key}[https://www.ruby-lang.org/security.asc]), which is a private mailing list.
16Reported problems will be published after fixes.
17
18== <code>$SAFE</code>
19
20Ruby provides a mechanism to restrict what operations can be performed by Ruby
21code in the form of the <code>$SAFE</code> variable.
22
23However, <code>$SAFE</code> does not provide a secure environment for executing
24untrusted code.
25
26If you need to execute untrusted code, you should use an operating system level
27sandboxing mechanism. On Linux, ptrace or LXC can be used to sandbox
28potentially malicious code. Other similar mechanisms exist on every major
29operating system.
30
31== +Marshal.load+
32
33Ruby's +Marshal+ module provides methods for serializing and deserializing Ruby
34object trees to and from a binary data format.
35
36Never use +Marshal.load+ to deserialize untrusted or user supplied data.
37Because +Marshal+ can deserialize to almost any Ruby object and has full
38control over instance variables, it is possible to craft a malicious payload
39that executes code shortly after deserialization.
40
41If you need to deserialize untrusted data, you should use JSON as it is only
42capable of returning 'primitive' types such as strings, arrays, hashes, numbers
43and nil. If you need to deserialize other classes, you should handle this
44manually. Never deserialize to a user specified class.
45
46== YAML
47
48YAML is a popular human readable data serialization format used by many Ruby
49programs for configuration and database persistence of Ruby object trees.
50
51Similar to +Marshal+, it is able to deserialize into arbitrary Ruby classes.
52For example, the following YAML data will create an +ERB+ object when
53deserialized:
54
55  !ruby/object:ERB
56  src: puts `uname`
57
58Because of this, many of the security considerations applying to Marshal are
59also applicable to YAML. Do not use YAML to deserialize untrusted data.
60
61== Symbols
62
63Symbols are often seen as syntax sugar for simple strings, but they play a much
64more crucial role. The MRI Ruby implementation uses Symbols internally for
65method, variable and constant names. The reason for this is that symbols are
66simply integers with names attached to them, so they are faster to look up in
67hashtables.
68
69Starting in version 2.2, most symbols can be garbage collected; these are
70called <i>mortal</i> symbols. Most symbols you create (e.g. by calling
71+to_sym+) are mortal.
72
73<i>Immortal</i> symbols on the other hand will never be garbage collected.
74They are created when modifying code:
75* defining a method (e.g. with +define_method+),
76* setting an instance variable (e.g. with +instance_variable_set+),
77* creating a variable or constant (e.g. with +const_set+)
78C extensions that have not been updated and are still calling `SYM2ID`
79will create immortal symbols.
80Bugs in 2.2.0: +send+ and +__send__+ also created immortal symbols,
81and calling methods with keyword arguments could also create some.
82
83Don't create immortal symbols from user inputs. Otherwise, this would
84allow a user to mount a denial of service attack against your application by
85flooding it with unique strings, which will cause memory to grow indefinitely
86until the Ruby process is killed or causes the system to slow to a halt.
87
88While it might not be a good idea to call these with user inputs, methods that
89used to be vulnerable such as +to_sym+, +respond_to?+,
90+method+, +instance_variable_get+, +const_get+, etc. are no longer a threat.
91
92== Regular expressions
93
94Ruby's regular expression syntax has some minor differences when compared to
95other languages. In Ruby, the <code>^</code> and <code>$</code> anchors do not
96refer to the beginning and end of the string, rather the beginning and end of a
97*line*.
98
99This means that if you're using a regular expression like
100<code>/^[a-z]+$/</code> to restrict a string to only letters, an attacker can
101bypass this check by passing a string containing a letter, then a newline, then
102any string of their choosing.
103
104If you want to match the beginning and end of the entire string in Ruby, use
105the anchors +\A+ and +\z+.
106
107== +eval+
108
109Never pass untrusted or user controlled input to +eval+.
110
111Unless you are implementing a REPL like +irb+ or +pry+, +eval+ is almost
112certainly not what you want. Do not attempt to filter user input before passing
113it to +eval+ - this approach is fraught with danger and will most likely open
114your application up to a serious remote code execution vulnerability.
115
116== +send+
117
118'Global functions' in Ruby (+puts+, +exit+, etc.) are actually private instance
119methods on +Object+. This means it is possible to invoke these methods with
120+send+, even if the call to +send+ has an explicit receiver.
121
122For example, the following code snippet writes "Hello world" to the terminal:
123
124  1.send(:puts, "Hello world")
125
126You should never call +send+ with user supplied input as the first parameter.
127Doing so can introduce a denial of service vulnerability:
128
129  foo.send(params[:bar]) # params[:bar] is "exit!"
130
131If an attacker can control the first two arguments to +send+, remote code
132execution is possible:
133
134  # params is { :a => "eval", :b => "...ruby code to be executed..." }
135  foo.send(params[:a], params[:b])
136
137When dispatching a method call based on user input, carefully verify that the
138method name. If possible, check it against a whitelist of safe method names.
139
140Note that the use of +public_send+ is also dangerous, as +send+ itself is
141public:
142
143  1.public_send("send", "eval", "...ruby code to be executed...")
144
145== DRb
146
147As DRb allows remote clients to invoke arbitrary methods, it is not suitable to
148expose to untrusted clients.
149
150When using DRb, try to avoid exposing it over the network if possible. If this
151isn't possible and you need to expose DRb to the world, you *must* configure an
152appropriate security policy with <code>DRb::ACL</code>.
153