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.