Use of Kernel.open, IO.read or similar sinks with user-controlled input¶
ID: rb/kernel-open
Kind: path-problem
Security severity: 9.8
Severity: error
Precision: high
Tags:
- correctness
- security
- external/cwe/cwe-078
- external/cwe/cwe-088
- external/cwe/cwe-073
Query suites:
- ruby-code-scanning.qls
- ruby-security-extended.qls
- ruby-security-and-quality.qls
Click to see the query in the CodeQL repository
If Kernel.open is given a file name that starts with a | character, it will execute the remaining string as a shell command. If a malicious user can control the file name, they can execute arbitrary code. The same vulnerability applies to IO.read, IO.write, IO.binread, IO.binwrite, IO.foreach, IO.readlines and URI.open.
Recommendation¶
Use File.open instead of Kernel.open, as the former does not have this vulnerability. Similarly, use the methods from the File class instead of the IO class e.g. File.read instead of IO.read.
Instead of URI.open use URI(..).open or an HTTP Client.
Example¶
The following example shows code that calls Kernel.open on a user-supplied file path.
require "open-uri"
class UsersController < ActionController::Base
def create
filename = params[:filename]
open(filename) # BAD
web_page = params[:web_page]
URI.open(web_page) # BAD - calls `Kernel.open` internally
end
end
Instead, File.open should be used, as in the following example.
class UsersController < ActionController::Base
def create
filename = params[:filename]
File.open(filename)
web_page = params[:web_page]
Net::HTTP.get(URI.parse(web_page))
end
end
References¶
OWASP: Command Injection. Ruby on Rails Cheat Sheet: Command Injection.
Example CVE: Command Injection in RDoc.
Common Weakness Enumeration: CWE-78.
Common Weakness Enumeration: CWE-88.
Common Weakness Enumeration: CWE-73.