mirror of
https://github.com/github/codeql.git
synced 2026-06-12 16:31:10 +02:00
Compare commits
7 Commits
copilot/ql
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
912dc9c0bd | ||
|
|
de7afcaec3 | ||
|
|
f3ec7087e3 | ||
|
|
bea5522473 | ||
|
|
eedef515f7 | ||
|
|
9078b511c6 | ||
|
|
01173bf383 |
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
* The query `actions/pr-on-self-hosted-runner` was updated to the latest standard runner labels reducing false positive results.
|
||||
@@ -2,10 +2,12 @@ import actions
|
||||
|
||||
bindingset[runner]
|
||||
predicate isGithubHostedRunner(string runner) {
|
||||
// list of github hosted repos: https://github.com/actions/runner-images/blob/main/README.md#available-images
|
||||
runner
|
||||
.toLowerCase()
|
||||
.regexpMatch("^(ubuntu-([0-9.]+|latest)|macos-([0-9]+|latest)(-x?large)?|windows-([0-9.]+|latest))$")
|
||||
// The list of github hosted repos:
|
||||
// https://github.com/actions/runner-images/blob/main/README.md#available-images
|
||||
// https://docs.github.com/en/enterprise-cloud@latest/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job#standard-github-hosted-runners-for-public-repositories
|
||||
runner.toLowerCase().regexpMatch("^ubuntu-([0-9.]+|latest|slim)(-arm)?$") or
|
||||
runner.toLowerCase().regexpMatch("^macos-([0-9]+|latest)(-x?large|-intel)?$") or
|
||||
runner.toLowerCase().regexpMatch("^windows-([0-9.]+|latest)(-vs[0-9.]+)?(-arm)?$")
|
||||
}
|
||||
|
||||
bindingset[runner]
|
||||
|
||||
43
actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml
vendored
Normal file
43
actions/ql/test/query-tests/Security/CWE-284/.github/workflows/test3.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- ubuntu-24.04
|
||||
- ubuntu-24.04-arm
|
||||
- ubuntu-22.04
|
||||
- ubuntu-22.04-arm
|
||||
- ubuntu-26.04
|
||||
- ubuntu-26.04-arm
|
||||
- ubuntu-slim
|
||||
- macos-26
|
||||
- macos-26-xlarge
|
||||
- macos-26-intel
|
||||
- macos-26-large
|
||||
- macos-latest-large
|
||||
- macos-15-large
|
||||
- macos-15
|
||||
- macos-15-intel
|
||||
- macos-latest
|
||||
- macos-15
|
||||
- macos-15-xlarge
|
||||
- macos-14-large
|
||||
- macos-14
|
||||
- macos-14-xlarge
|
||||
- windows-2025-vs2026
|
||||
- windows-latest
|
||||
- windows-2025
|
||||
- windows-2022
|
||||
- windows-11
|
||||
- windows-11-arm
|
||||
- windows-11-vs2026-arm
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- run: cmd
|
||||
@@ -203,7 +203,7 @@ module Ast implements AstSig<Location> {
|
||||
final private class FinalTryStmt = CS::TryStmt;
|
||||
|
||||
class TryStmt extends FinalTryStmt {
|
||||
Stmt getBody() { result = this.getBlock() }
|
||||
AstNode getBody(int index) { index = 0 and result = this.getBlock() }
|
||||
|
||||
CatchClause getCatch(int index) { result = this.getCatchClause(index) }
|
||||
|
||||
|
||||
@@ -117,15 +117,18 @@ private module Ast implements AstSig<Location> {
|
||||
final private class FinalTryStmt = J::TryStmt;
|
||||
|
||||
class TryStmt extends FinalTryStmt {
|
||||
Stmt getBody() { result = super.getBlock() }
|
||||
AstNode getBody(int index) {
|
||||
result = super.getResource(index)
|
||||
or
|
||||
index = count(super.getAResource()) and
|
||||
result = super.getBlock()
|
||||
}
|
||||
|
||||
CatchClause getCatch(int index) { result = super.getCatchClause(index) }
|
||||
|
||||
Stmt getFinally() { result = super.getFinally() }
|
||||
}
|
||||
|
||||
AstNode getTryInit(TryStmt try, int index) { result = try.getResource(index) }
|
||||
|
||||
final private class FinalCatchClause = J::CatchClause;
|
||||
|
||||
class CatchClause extends FinalCatchClause {
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/CWE-522-DecompressionBombs/DecompressionBombs.ql
|
||||
@@ -1,27 +1,27 @@
|
||||
require 'zlib'
|
||||
|
||||
class TestController < ActionController::Base
|
||||
gzip_path = params[:path] # $ Source
|
||||
gzip_path = params[:path]
|
||||
|
||||
Zlib::GzipReader.open(gzip_path).read # $ Alert
|
||||
Zlib::GzipReader.open(gzip_path).read
|
||||
Zlib::GzipReader.open(gzip_path) do |uncompressedfile|
|
||||
puts uncompressedfile.read
|
||||
end # $ Alert
|
||||
end
|
||||
Zlib::GzipReader.open(gzip_path) do |uncompressedfile|
|
||||
uncompressedfile.each do |entry|
|
||||
puts entry
|
||||
end
|
||||
end # $ Alert
|
||||
uncompressedfile = Zlib::GzipReader.open(gzip_path) # $ Alert
|
||||
end
|
||||
uncompressedfile = Zlib::GzipReader.open(gzip_path)
|
||||
uncompressedfile.each do |entry|
|
||||
puts entry
|
||||
end
|
||||
|
||||
Zlib::GzipReader.new(File.open(gzip_path, 'rb')).read # $ Alert
|
||||
Zlib::GzipReader.new(File.open(gzip_path, 'rb')).each do |entry| # $ Alert
|
||||
Zlib::GzipReader.new(File.open(gzip_path, 'rb')).read
|
||||
Zlib::GzipReader.new(File.open(gzip_path, 'rb')).each do |entry|
|
||||
puts entry
|
||||
end
|
||||
|
||||
Zlib::GzipReader.zcat(open(gzip_path)) # $ Alert
|
||||
Zlib::GzipReader.zcat(open(gzip_path))
|
||||
end
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
require 'zip'
|
||||
|
||||
class TestController < ActionController::Base
|
||||
zipfile_path = params[:path] # $ Source
|
||||
zipfile_path = params[:path]
|
||||
|
||||
Zip::InputStream.open(zipfile_path) do |input|
|
||||
while (entry = input.get_next_entry)
|
||||
puts :file_name, entry.name
|
||||
input
|
||||
end
|
||||
end # $ Alert
|
||||
end
|
||||
Zip::InputStream.open(zipfile_path) do |input|
|
||||
input.read
|
||||
end # $ Alert
|
||||
input = Zip::InputStream.open(zipfile_path) # $ Alert
|
||||
end
|
||||
input = Zip::InputStream.open(zipfile_path)
|
||||
|
||||
Zip::File.open(zipfile_path).read "10GB" # $ Alert
|
||||
Zip::File.open(zipfile_path).extract "10GB", "./" # $ Alert
|
||||
Zip::File.open(zipfile_path).read "10GB"
|
||||
Zip::File.open(zipfile_path).extract "10GB", "./"
|
||||
|
||||
Zip::File.open(zipfile_path) do |zip_file|
|
||||
# Handle entries one by one
|
||||
@@ -25,33 +25,33 @@ class TestController < ActionController::Base
|
||||
# Extract to file or directory based on name in the archive
|
||||
entry.extract
|
||||
# Read into memory
|
||||
entry.get_input_stream.read # $ Alert
|
||||
entry.get_input_stream.read
|
||||
end
|
||||
end
|
||||
|
||||
zip_file = Zip::File.open(zipfile_path)
|
||||
zip_file.each do |entry|
|
||||
entry.extract # $ Alert
|
||||
entry.get_input_stream.read # $ Alert
|
||||
entry.extract
|
||||
entry.get_input_stream.read
|
||||
end
|
||||
|
||||
# Find specific entry
|
||||
Zip::File.open(zipfile_path) do |zip_file|
|
||||
zip_file.glob('*.xml').each do |entry|
|
||||
zip_file.read(entry.name) # $ Alert
|
||||
entry.extract # $ Alert
|
||||
zip_file.read(entry.name)
|
||||
entry.extract
|
||||
end
|
||||
entry = zip_file.glob('*.csv').first
|
||||
raise 'File too large when extracted' if entry.size > MAX_SIZE
|
||||
puts entry.get_input_stream.read # $ Alert
|
||||
puts entry.get_input_stream.read
|
||||
end
|
||||
|
||||
zip_file = Zip::File.open(zipfile_path)
|
||||
entry = zip_file.glob('*.csv')
|
||||
puts entry.get_input_stream.read # $ Alert
|
||||
puts entry.get_input_stream.read
|
||||
|
||||
zip_file = Zip::File.open(zipfile_path)
|
||||
zip_file.glob('*') do |entry|
|
||||
entry.get_input_stream.read # $ Alert
|
||||
entry.get_input_stream.read
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/ldap-improper-auth/ImproperLdapAuth.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/ldap-improper-auth/ImproperLdapAuth.ql
|
||||
@@ -2,7 +2,7 @@ class FooController < ActionController::Base
|
||||
def some_request_handler
|
||||
# A string tainted by user input is used directly as password
|
||||
# (i.e a remote flow source)
|
||||
pass = params[:pass] # $ Source
|
||||
pass = params[:pass]
|
||||
|
||||
# BAD: user input is not sanitized
|
||||
ldap = Net::LDAP.new(
|
||||
@@ -12,7 +12,7 @@ class FooController < ActionController::Base
|
||||
auth: {
|
||||
method: :simple,
|
||||
username: 'uid=admin,dc=example,dc=com',
|
||||
password: pass # $ Alert
|
||||
password: pass
|
||||
}
|
||||
)
|
||||
ldap.bind
|
||||
@@ -21,14 +21,14 @@ class FooController < ActionController::Base
|
||||
def some_request_handler
|
||||
# A string tainted by user input is used directly as password
|
||||
# (i.e a remote flow source)
|
||||
pass = params[:pass] # $ Source
|
||||
pass = params[:pass]
|
||||
|
||||
# BAD: user input is not sanitized
|
||||
ldap = Net::LDAP.new
|
||||
ldap.host = your_server_ip_address
|
||||
ldap.encryption(:method => :simple_tls)
|
||||
ldap.port = 639
|
||||
ldap.auth "admin", pass # $ Alert
|
||||
ldap.auth "admin", pass
|
||||
ldap.bind
|
||||
end
|
||||
end
|
||||
@@ -56,4 +56,4 @@ class BarController < ApplicationController
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/insecure-randomness/InsecureRandomness.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/insecure-randomness/InsecureRandomness.ql
|
||||
@@ -3,7 +3,7 @@ require 'securerandom'
|
||||
def generate_password_1(length)
|
||||
chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['!', '@', '#', '$', '%']
|
||||
# BAD: rand is not cryptographically secure
|
||||
password = (1..length).collect { chars[rand(chars.size)] }.join # $ Alert
|
||||
password = (1..length).collect { chars[rand(chars.size)] }.join
|
||||
end
|
||||
|
||||
def generate_password_2(length)
|
||||
@@ -16,4 +16,4 @@ def generate_password_2(length)
|
||||
end
|
||||
|
||||
password = generate_password_1(10)
|
||||
password = generate_password_2(10)
|
||||
password = generate_password_2(10)
|
||||
@@ -2,11 +2,11 @@ class FooController < ActionController::Base
|
||||
def some_request_handler
|
||||
# A string tainted by user input is used directly as DN
|
||||
# (i.e a remote flow source)
|
||||
dc = params[:dc] # $ Source
|
||||
dc = params[:dc]
|
||||
|
||||
# A string tainted by user input is used directly as search filter or attribute
|
||||
# (i.e a remote flow source)
|
||||
name = params[:user_name] # $ Source
|
||||
name = params[:user_name]
|
||||
|
||||
# LDAP Connection
|
||||
ldap = Net::LDAP.new(
|
||||
@@ -22,20 +22,20 @@ class FooController < ActionController::Base
|
||||
|
||||
# BAD: user input is used as DN
|
||||
# where dc is unsanitized
|
||||
ldap.search(base: "ou=people,dc=#{dc},dc=com", filter: "cn=George", attributes: [""]) # $ Alert
|
||||
ldap.search(base: "ou=people,dc=#{dc},dc=com", filter: "cn=George", attributes: [""])
|
||||
|
||||
# BAD: user input is used as search filter
|
||||
# where name is unsanitized
|
||||
ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=#{name}", attributes: [""]) # $ Alert
|
||||
ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=#{name}", attributes: [""])
|
||||
|
||||
# BAD: user input is used as attribute
|
||||
# where name is unsanitized
|
||||
ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=George", attributes: [name]) # $ Alert
|
||||
ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=George", attributes: [name])
|
||||
|
||||
# BAD: user input is used as search filter
|
||||
# where name is unsanitized
|
||||
filter = Net::LDAP::Filter.eq('cn', name)
|
||||
ldap.search(base: "ou=people,dc=example,dc=com", filter: filter, attributes: [""]) # $ Alert
|
||||
ldap.search(base: "ou=people,dc=example,dc=com", filter: filter, attributes: [""])
|
||||
|
||||
# GOOD: user input is not used in the LDAP query
|
||||
result = ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=George", attributes: [""])
|
||||
@@ -63,4 +63,4 @@ class BarController < ApplicationController
|
||||
end
|
||||
result = ldap.search(base: "ou=people,dc=example,dc=com", filter: "cn=#{name}", attributes: [""])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/ldap-injection/LdapInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/ldap-injection/LdapInjection.ql
|
||||
@@ -2,7 +2,7 @@ class FooController < ActionController::Base
|
||||
def some_request_handler
|
||||
# A string tainted by user input is inserted into a template
|
||||
# (i.e a remote flow source)
|
||||
name = params[:name] # $ Source
|
||||
name = params[:name]
|
||||
|
||||
# Template with the source
|
||||
bad_text = "
|
||||
@@ -12,11 +12,11 @@ class FooController < ActionController::Base
|
||||
|
||||
# BAD: user input is evaluated
|
||||
# where name is unsanitized
|
||||
template = ERB.new(bad_text).result(binding) # $ Alert
|
||||
template = ERB.new(bad_text).result(binding)
|
||||
|
||||
# BAD: user input is evaluated
|
||||
# where name is unsanitized
|
||||
render inline: bad_text # $ Alert
|
||||
render inline: bad_text
|
||||
|
||||
# Template with the source
|
||||
good_text = "
|
||||
|
||||
@@ -2,7 +2,7 @@ class FooController < ActionController::Base
|
||||
def some_request_handler
|
||||
# A string tainted by user input is inserted into a template
|
||||
# (i.e a remote flow source)
|
||||
name = params[:name] # $ Source
|
||||
name = params[:name]
|
||||
|
||||
# Template with the source (no sanitizer)
|
||||
bad_text = "
|
||||
@@ -11,7 +11,7 @@ class FooController < ActionController::Base
|
||||
" % name
|
||||
# BAD: renders user input
|
||||
# where text is unsanitized
|
||||
Slim::Template.new{ bad_text }.render # $ Alert
|
||||
Slim::Template.new{ bad_text }.render
|
||||
|
||||
# Template with the source (no sanitizer)
|
||||
bad2_text = "
|
||||
@@ -20,7 +20,7 @@ class FooController < ActionController::Base
|
||||
"
|
||||
# BAD: renders user input
|
||||
# where text is unsanitized
|
||||
Slim::Template.new{ bad2_text }.render # $ Alert
|
||||
Slim::Template.new{ bad2_text }.render
|
||||
|
||||
# Template with the source (no render)
|
||||
good_text = "
|
||||
@@ -64,4 +64,4 @@ class BarController < ApplicationController
|
||||
" % name2
|
||||
template_bar1 = Slim::Template.new{ text_bar2 }.render
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/template-injection/TemplateInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/template-injection/TemplateInjection.ql
|
||||
@@ -2,7 +2,7 @@ require 'libxml'
|
||||
|
||||
class FooController < ActionController::Base
|
||||
def libxml_handler(event:, context:)
|
||||
name = params[:user_name] # $ Source
|
||||
name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
@@ -18,13 +18,13 @@ class FooController < ActionController::Base
|
||||
results1 = doc.find_first('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results2 = doc.find_first("//#{name}") # $ Alert
|
||||
results2 = doc.find_first("//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results3 = doc.find('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results4 = doc.find("//#{name}") # $ Alert
|
||||
results4 = doc.find("//#{name}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ require 'nokogiri'
|
||||
|
||||
class FooController < ActionController::Base
|
||||
def nokogiri_handler(event:, context:)
|
||||
name = params[:user_name] # $ Source
|
||||
name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
@@ -18,19 +18,19 @@ class FooController < ActionController::Base
|
||||
results1 = doc.at('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results2 = doc.at("//#{name}") # $ Alert
|
||||
results2 = doc.at("//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results3 = doc.xpath('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results4 = doc.xpath("//#{name}") # $ Alert
|
||||
results4 = doc.xpath("//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results5 = doc.at_xpath('//foo')
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results6 = doc.at_xpath("//#{name}") # $ Alert
|
||||
results6 = doc.at_xpath("//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
doc.xpath('//foo').each do |element|
|
||||
@@ -38,7 +38,7 @@ class FooController < ActionController::Base
|
||||
end
|
||||
|
||||
# BAD: XPath query constructed from user input
|
||||
doc.xpath("//#{name}").each do |element| # $ Alert
|
||||
doc.xpath("//#{name}").each do |element|
|
||||
puts element.text
|
||||
end
|
||||
|
||||
@@ -48,7 +48,7 @@ class FooController < ActionController::Base
|
||||
end
|
||||
|
||||
# BAD: XPath query constructed from user input
|
||||
doc.search("//#{name}").each do |element| # $ Alert
|
||||
doc.search("//#{name}").each do |element|
|
||||
puts element.text
|
||||
end
|
||||
end
|
||||
@@ -85,4 +85,4 @@ class BarController < ActionController::Base
|
||||
results9 = doc.at_xpath("//#{safe_name}")
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,7 @@ require 'rexml'
|
||||
|
||||
class FooController < ActionController::Base
|
||||
def rexml_handler(event:, context:)
|
||||
name = params[:user_name] # $ Source
|
||||
name = params[:user_name]
|
||||
|
||||
xml = <<-XML
|
||||
<root>
|
||||
@@ -18,13 +18,13 @@ class FooController < ActionController::Base
|
||||
results1 = REXML::XPath.first(doc, "//foo")
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results2 = REXML::XPath.first(doc, "//#{name}") # $ Alert
|
||||
results2 = REXML::XPath.first(doc, "//#{name}")
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
results3 = REXML::XPath.match(doc, "//foo", nil)
|
||||
|
||||
# BAD: XPath query is constructed from user input
|
||||
results4 = REXML::XPath.match(doc, "//#{name}", nil) # $ Alert
|
||||
results4 = REXML::XPath.match(doc, "//#{name}", nil)
|
||||
|
||||
# GOOD: XPath query is not constructed from user input
|
||||
REXML::XPath.each(doc, "//foo") do |element|
|
||||
@@ -32,7 +32,7 @@ class FooController < ActionController::Base
|
||||
end
|
||||
|
||||
# BAD: XPath query constructed from user input
|
||||
REXML::XPath.each(doc, "//#{name}") do |element| # $ Alert
|
||||
REXML::XPath.each(doc, "//#{name}") do |element|
|
||||
puts element.text
|
||||
end
|
||||
end
|
||||
@@ -66,4 +66,4 @@ class BarController < ActionController::Base
|
||||
results6 = REXML::XPath.match(doc, "//#{safe_name}", nil)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/xpath-injection/XpathInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/xpath-injection/XpathInjection.ql
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/cwe-022-zipslip/ZipSlip.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/cwe-022-zipslip/ZipSlip.ql
|
||||
|
||||
@@ -5,9 +5,9 @@ class TestController < ActionController::Base
|
||||
def tarReaderUnsafe
|
||||
path = params[:path]
|
||||
file_stream = IO.new(IO.sysopen(path))
|
||||
tarfile = Gem::Package::TarReader.new(file_stream) # $ Source
|
||||
tarfile = Gem::Package::TarReader.new(file_stream)
|
||||
tarfile.each do |entry|
|
||||
::File.open(entry.full_name, "wb") do |os| # $ Alert
|
||||
::File.open(entry.full_name, "wb") do |os|
|
||||
entry.read
|
||||
end
|
||||
end
|
||||
@@ -17,9 +17,9 @@ class TestController < ActionController::Base
|
||||
def tarReaderBlockUnsafe
|
||||
path = params[:path]
|
||||
file_stream = IO.new(IO.sysopen(path))
|
||||
Gem::Package::TarReader.new(file_stream) do |tarfile| # $ Source
|
||||
Gem::Package::TarReader.new(file_stream) do |tarfile|
|
||||
tarfile.each_entry do |entry|
|
||||
::File.open(entry.full_name, "wb") do |os| # $ Alert
|
||||
::File.open(entry.full_name, "wb") do |os|
|
||||
entry.read
|
||||
end
|
||||
end
|
||||
@@ -43,8 +43,8 @@ class TestController < ActionController::Base
|
||||
# BAD
|
||||
def zipFileUnsafe
|
||||
path = params[:path]
|
||||
Zip::File.open(path).each do |entry| # $ Source
|
||||
File.open(entry.name, "wb") do |os| # $ Alert
|
||||
Zip::File.open(path).each do |entry|
|
||||
File.open(entry.name, "wb") do |os|
|
||||
entry.read
|
||||
end
|
||||
end
|
||||
@@ -53,9 +53,9 @@ class TestController < ActionController::Base
|
||||
# BAD
|
||||
def zipFileBlockUnsafe
|
||||
path = params[:path]
|
||||
Zip::File.open(path) do |zip_file| # $ Source
|
||||
Zip::File.open(path) do |zip_file|
|
||||
zip_file.each do |entry|
|
||||
File.open(entry.name, "wb") do |os| # $ Alert
|
||||
File.open(entry.name, "wb") do |os|
|
||||
entry.read
|
||||
end
|
||||
end
|
||||
@@ -87,7 +87,7 @@ class TestController < ActionController::Base
|
||||
end
|
||||
|
||||
def get_compressed_file_stream(compressed_file_path)
|
||||
gzip = Zlib::GzipReader.open(compressed_file_path) # $ Source
|
||||
gzip = Zlib::GzipReader.open(compressed_file_path)
|
||||
yield(gzip)
|
||||
end
|
||||
|
||||
@@ -97,7 +97,7 @@ class TestController < ActionController::Base
|
||||
get_compressed_file_stream(path) do |compressed_file|
|
||||
compressed_file.each do |entry|
|
||||
entry_path = entry.full_name
|
||||
::File.open(entry_path, 'wb') do |os| # $ Alert
|
||||
::File.open(entry_path, 'wb') do |os|
|
||||
entry.read
|
||||
end
|
||||
end
|
||||
@@ -120,10 +120,10 @@ class TestController < ActionController::Base
|
||||
def gzipReaderUnsafeNewInstance
|
||||
path = params[:path]
|
||||
File.open(path, 'rb') do |f|
|
||||
gz = Zlib::GzipReader.new(f) # $ Source
|
||||
gz = Zlib::GzipReader.new(f)
|
||||
gz.each do |entry|
|
||||
entry_path = entry.full_name
|
||||
::File.open(entry_path, 'wb') do |os| # $ Alert
|
||||
::File.open(entry_path, 'wb') do |os|
|
||||
entry.read
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/cwe-176/UnicodeBypassValidation.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/cwe-176/UnicodeBypassValidation.ql
|
||||
|
||||
@@ -4,35 +4,35 @@ require 'cgi'
|
||||
|
||||
class UnicodeNormalizationOKController < ActionController::Base
|
||||
def unicodeNormalize
|
||||
unicode_input = params[:unicode_input] # $ Source
|
||||
normalized_nfkc = unicode_input.unicode_normalize(:nfkc) # $ Alert // $ MISSING:result=OK
|
||||
normalized_nfc = unicode_input.unicode_normalize(:nfc) # $ Alert // $ MISSING:result=OK
|
||||
unicode_input = params[:unicode_input]
|
||||
normalized_nfkc = unicode_input.unicode_normalize(:nfkc) # $ MISSING:result=OK
|
||||
normalized_nfc = unicode_input.unicode_normalize(:nfc) # $ MISSING:result=OK
|
||||
end
|
||||
end
|
||||
|
||||
class UnicodeNormalizationStrManipulationController < ActionController::Base
|
||||
def unicodeNormalize
|
||||
unicode_input = params[:unicode_input] # $ Source
|
||||
unicode_input_manip = unicode_input.sub(/[aeiou]/, "*") # $ Source
|
||||
normalized_nfkc = unicode_input_manip.unicode_normalize(:nfkc) # $ Alert // $ result=BAD
|
||||
normalized_nfc = unicode_input_manip.unicode_normalize(:nfc) # $ Alert // $ result=BAD
|
||||
unicode_input = params[:unicode_input]
|
||||
unicode_input_manip = unicode_input.sub(/[aeiou]/, "*")
|
||||
normalized_nfkc = unicode_input_manip.unicode_normalize(:nfkc) # $ result=BAD
|
||||
normalized_nfc = unicode_input_manip.unicode_normalize(:nfc) # $ result=BAD
|
||||
end
|
||||
end
|
||||
|
||||
class UnicodeNormalizationHtMLEscapeController < ActionController::Base
|
||||
def unicodeNormalize
|
||||
unicode_input = params[:unicode_input] # $ Source
|
||||
unicode_html_safe = html_escape(unicode_input) # $ Source
|
||||
normalized_nfkc = unicode_html_safe.unicode_normalize(:nfkc) # $ Alert // $ result=BAD
|
||||
normalized_nfc = unicode_html_safe.unicode_normalize(:nfc) # $ Alert // $ result=BAD
|
||||
unicode_input = params[:unicode_input]
|
||||
unicode_html_safe = html_escape(unicode_input)
|
||||
normalized_nfkc = unicode_html_safe.unicode_normalize(:nfkc) # $ result=BAD
|
||||
normalized_nfc = unicode_html_safe.unicode_normalize(:nfc) # $ result=BAD
|
||||
end
|
||||
end
|
||||
|
||||
class UnicodeNormalizationCGIHtMLEscapeController < ActionController::Base
|
||||
def unicodeNormalize
|
||||
unicode_input = params[:unicode_input] # $ Source
|
||||
unicode_html_safe = CGI.escapeHTML(unicode_input).html_safe # $ Source
|
||||
normalized_nfkc = unicode_html_safe.unicode_normalize(:nfkd) # $ Alert // $ result=BAD
|
||||
normalized_nfc = unicode_html_safe.unicode_normalize(:nfd) # $ Alert // $ result=BAD
|
||||
unicode_input = params[:unicode_input]
|
||||
unicode_html_safe = CGI.escapeHTML(unicode_input).html_safe
|
||||
normalized_nfkc = unicode_html_safe.unicode_normalize(:nfkd) # $ result=BAD
|
||||
normalized_nfc = unicode_html_safe.unicode_normalize(:nfd) # $ result=BAD
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/cwe-347/EmptyJWTSecret.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/cwe-347/EmptyJWTSecret.ql
|
||||
@@ -6,10 +6,10 @@ payload = { foo: 'bar' }
|
||||
token1 = JWT.encode({ foo: 'bar' }, "secret", 'none')
|
||||
|
||||
# BAD: the secret used is empty
|
||||
token2 = JWT.encode({ foo: 'bar' }, nil, 'HS256') # $ Alert[rb/jwt-empty-secret-or-algorithm]
|
||||
token2 = JWT.encode({ foo: 'bar' }, nil, 'HS256')
|
||||
|
||||
# BAD: the secret used is empty
|
||||
token3 = JWT.encode({ foo: 'bar' }, "", 'HS256') # $ Alert[rb/jwt-empty-secret-or-algorithm]
|
||||
token3 = JWT.encode({ foo: 'bar' }, "", 'HS256')
|
||||
|
||||
# GOOD: the token is signed
|
||||
token4 = JWT.encode({ foo: 'bar' }, "secret", 'HS256')
|
||||
token4 = JWT.encode({ foo: 'bar' }, "secret", 'HS256')
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/cwe-347/MissingJWTVerification.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/cwe-347/MissingJWTVerification.ql
|
||||
@@ -3,22 +3,22 @@ require 'jwt'
|
||||
payload = { foo: 'bar' }
|
||||
|
||||
# Unsecure token
|
||||
token_without_signature = JWT.encode(payload, nil, 'none') # $ Alert[rb/jwt-empty-secret-or-algorithm]
|
||||
token_without_signature = JWT.encode(payload, nil, 'none')
|
||||
|
||||
# Secure token
|
||||
token = JWT.encode(payload, "secret", 'HS256')
|
||||
|
||||
# BAD: it does not verify
|
||||
decoded_token1 = JWT.decode(token_without_signature, nil, false, algorithm: 'HS256') # $ Alert[rb/jwt-missing-verification]
|
||||
decoded_token1 = JWT.decode(token_without_signature, nil, false, algorithm: 'HS256')
|
||||
|
||||
# BAD: it's using none
|
||||
decoded_token3 = JWT.decode(token_without_signature, secret, true, algorithm: 'none') # $ Alert[rb/jwt-missing-verification]
|
||||
decoded_token3 = JWT.decode(token_without_signature, secret, true, algorithm: 'none')
|
||||
|
||||
# BAD: it's using none
|
||||
decoded_token4 = JWT.decode(token_without_signature, secret, true, { algorithm: 'none' }) # $ Alert[rb/jwt-missing-verification]
|
||||
decoded_token4 = JWT.decode(token_without_signature, secret, true, { algorithm: 'none' })
|
||||
|
||||
# GOOD: it does verify
|
||||
decoded_token5 = JWT.decode(token, secret, 'HS256')
|
||||
|
||||
# GOOD: it does verify
|
||||
decoded_token2 = JWT.decode(token,secret)
|
||||
decoded_token2 = JWT.decode(token,secret)
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/cwe-502/UnsafeYamlDeserialization.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/cwe-502/UnsafeYamlDeserialization.ql
|
||||
@@ -7,15 +7,15 @@ require "yaml"
|
||||
class UsersController < ActionController::Base
|
||||
# BAD before psych version 4.0.0 and
|
||||
def route1
|
||||
yaml_data = params[:key] # $ Source
|
||||
object = Psych.load yaml_data # $ Alert
|
||||
yaml_data = params[:key]
|
||||
object = Psych.load yaml_data
|
||||
object = Psych.load_file yaml_data
|
||||
end
|
||||
|
||||
# GOOD In psych version 4.0.0 and above
|
||||
def route2
|
||||
yaml_data = params[:key] # $ Source
|
||||
object = Psych.load yaml_data # $ Alert
|
||||
yaml_data = params[:key]
|
||||
object = Psych.load yaml_data
|
||||
object = Psych.load_file yaml_data
|
||||
end
|
||||
|
||||
@@ -29,14 +29,14 @@ class UsersController < ActionController::Base
|
||||
|
||||
# BAD
|
||||
def route4
|
||||
yaml_data = params[:key] # $ Source
|
||||
object = Psych.unsafe_load(yaml_data) # $ Alert
|
||||
object = Psych.unsafe_load_file(yaml_data) # $ Alert
|
||||
object = Psych.load_stream(yaml_data) # $ Alert
|
||||
yaml_data = params[:key]
|
||||
object = Psych.unsafe_load(yaml_data)
|
||||
object = Psych.unsafe_load_file(yaml_data)
|
||||
object = Psych.load_stream(yaml_data)
|
||||
parse_output = Psych.parse_stream(yaml_data)
|
||||
object = parse_output.to_ruby # $ Alert
|
||||
object = Psych.parse(yaml_data).to_ruby # $ Alert
|
||||
object = Psych.parse_file(yaml_data).to_ruby # $ Alert
|
||||
object = parse_output.to_ruby
|
||||
object = Psych.parse(yaml_data).to_ruby
|
||||
object = Psych.parse_file(yaml_data).to_ruby
|
||||
parsed_yaml = Psych.parse_stream(yaml_data)
|
||||
parsed_yaml.children.each do |child|
|
||||
object = child.to_ruby
|
||||
@@ -46,7 +46,7 @@ class UsersController < ActionController::Base
|
||||
end
|
||||
object = parsed_yaml.children.first.to_ruby
|
||||
content = parsed_yaml.children[0].children[0].children
|
||||
object = parsed_yaml.to_ruby[0] # $ Alert
|
||||
object = parsed_yaml.to_ruby[0]
|
||||
object = content.to_ruby[0]
|
||||
object = Psych.parse(yaml_data).children[0].to_ruby
|
||||
end
|
||||
@@ -58,18 +58,18 @@ class UsersController < ActionController::Base
|
||||
end
|
||||
|
||||
def stdin
|
||||
object = YAML.load $stdin.read # $ Alert
|
||||
object = YAML.load $stdin.read
|
||||
|
||||
# STDIN
|
||||
object = YAML.load STDIN.gets # $ Alert
|
||||
object = YAML.load STDIN.gets
|
||||
|
||||
# ARGF
|
||||
object = YAML.load ARGF.read # $ Alert
|
||||
object = YAML.load ARGF.read
|
||||
|
||||
# Kernel.gets
|
||||
object = YAML.load gets # $ Alert
|
||||
object = YAML.load gets
|
||||
|
||||
# Kernel.readlines
|
||||
object = YAML.load readlines # $ Alert
|
||||
object = YAML.load readlines
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/manually-check-http-verb/ManuallyCheckHttpVerb.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/manually-check-http-verb/ManuallyCheckHttpVerb.ql
|
||||
@@ -1,39 +1,39 @@
|
||||
class ExampleController < ActionController::Base
|
||||
# Should find
|
||||
def example_action
|
||||
if request.get? # $ Alert
|
||||
if request.get?
|
||||
Resource.find(id: params[:example_id])
|
||||
end
|
||||
end
|
||||
|
||||
# Should find
|
||||
def other_action
|
||||
method = request.env['REQUEST_METHOD'] # $ Source
|
||||
if method == "GET" # $ Alert
|
||||
method = request.env['REQUEST_METHOD']
|
||||
if method == "GET"
|
||||
Resource.find(id: params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
# Should find
|
||||
def foo
|
||||
method = request.request_method # $ Source
|
||||
if method == "GET" # $ Alert
|
||||
method = request.request_method
|
||||
if method == "GET"
|
||||
Resource.find(id: params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
# Should find
|
||||
def bar
|
||||
method = request.method # $ Source
|
||||
if method == "GET" # $ Alert
|
||||
method = request.method
|
||||
if method == "GET"
|
||||
Resource.find(id: params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
# Should find
|
||||
def baz
|
||||
method = request.raw_request_method # $ Source
|
||||
if method == "GET" # $ Alert
|
||||
method = request.raw_request_method
|
||||
if method == "GET"
|
||||
Resource.find(id: params[:id])
|
||||
end
|
||||
end
|
||||
@@ -48,15 +48,15 @@ class ExampleController < ActionController::Base
|
||||
|
||||
# Should find
|
||||
def foobarbaz
|
||||
method = request.request_method_symbol # $ Source
|
||||
if method == :GET # $ Alert
|
||||
method = request.request_method_symbol
|
||||
if method == :GET
|
||||
Resource.find(id: params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
# Should find
|
||||
def resource_action
|
||||
case request.env['REQUEST_METHOD'] # $ Alert
|
||||
case request.env['REQUEST_METHOD']
|
||||
when "GET"
|
||||
Resource.find(id: params[:id])
|
||||
when "POST"
|
||||
@@ -114,4 +114,4 @@ class NotAController
|
||||
end
|
||||
|
||||
class Resource < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/weak-params/WeakParams.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/weak-params/WeakParams.ql
|
||||
@@ -2,22 +2,22 @@ class TestController < ActionController::Base
|
||||
|
||||
# Should catch
|
||||
def create
|
||||
TestObject.create(foo: request.request_parameters[:foo]) # $ Alert
|
||||
TestObject.create(foo: request.request_parameters[:foo])
|
||||
end
|
||||
|
||||
# Should catch
|
||||
def create_query
|
||||
TestObject.create(foo: request.query_parameters[:foo]) # $ Alert
|
||||
TestObject.create(foo: request.query_parameters[:foo])
|
||||
end
|
||||
|
||||
# Should catch
|
||||
def update_unsafe
|
||||
TestObject.update(foo: request.POST[:foo]) # $ Alert
|
||||
TestObject.update(foo: request.POST[:foo])
|
||||
end
|
||||
|
||||
# Should catch
|
||||
def update_unsafe_get
|
||||
TestObject.update(foo: request.GET[:foo]) # $ Alert
|
||||
TestObject.update(foo: request.GET[:foo])
|
||||
end
|
||||
|
||||
# Should not catch
|
||||
@@ -37,4 +37,4 @@ class TestController < ActionController::Base
|
||||
end
|
||||
|
||||
class TestObject < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
@@ -1,2 +1 @@
|
||||
query: experimental/performance/UseDetect.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
experimental/performance/UseDetect.ql
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
class DetectTest
|
||||
def test
|
||||
# These are bad
|
||||
[].select { |i| true }.first # $ Alert
|
||||
[].select { |i| true }.last # $ Alert
|
||||
[].select { |i| true }[0] # $ Alert
|
||||
[].select { |i| true }[-1] # $ Alert
|
||||
[].filter { |i| true }.first # $ Alert
|
||||
[].find_all { |i| true }.last # $ Alert
|
||||
[].select { |i| true }.first
|
||||
[].select { |i| true }.last
|
||||
[].select { |i| true }[0]
|
||||
[].select { |i| true }[-1]
|
||||
[].filter { |i| true }.first
|
||||
[].find_all { |i| true }.last
|
||||
selection1 = [].select { |i| true }
|
||||
selection1.first # $ Alert
|
||||
selection1.first
|
||||
|
||||
# These are good
|
||||
[].select("").first # Selecting a string
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-020/IncompleteHostnameRegExp.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-020/IncompleteHostnameRegExp.ql
|
||||
@@ -1,6 +1,6 @@
|
||||
UNSAFE_REGEX1 = /(www|beta).example.com\// # $ Alert
|
||||
UNSAFE_REGEX2 = Regexp.compile("(www|beta).example.com/") # $ Alert
|
||||
UNSAFE_REGEX3 = Regexp.new("(www|beta).example.com/") # $ Alert
|
||||
UNSAFE_REGEX1 = /(www|beta).example.com\//
|
||||
UNSAFE_REGEX2 = Regexp.compile("(www|beta).example.com/")
|
||||
UNSAFE_REGEX3 = Regexp.new("(www|beta).example.com/")
|
||||
SAFE_REGEX = /(www|beta)\.example\.com\//
|
||||
|
||||
def unsafe
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
def foo
|
||||
/^http:\/\/example.com/; # OK
|
||||
/^http:\/\/test.example.com/; # $ Alert // NOT OK
|
||||
/^http:\/\/test.example.com/; # NOT OK
|
||||
/^http:\/\/test\.example.com/; # OK
|
||||
/^http:\/\/test.example.net/; # $ Alert // NOT OK
|
||||
/^http:\/\/test.(example-a|example-b).com/; # $ Alert // NOT OK
|
||||
/^http:\/\/(.+).example.com\//; # $ Alert // NOT OK
|
||||
/^http:\/\/test.example.net/; # NOT OK
|
||||
/^http:\/\/test.(example-a|example-b).com/; # NOT OK
|
||||
/^http:\/\/(.+).example.com\//; # NOT OK
|
||||
/^http:\/\/(\.+)\.example.com/; # OK
|
||||
/^http:\/\/(?:.+)\.test\.example.com\//; # $ Alert // NOT OK
|
||||
/^http:\/\/test.example.com\/(?:.*)/; # $ Alert // OK
|
||||
Regexp.new("^http://test.example.com"); # $ Alert // NOT OK
|
||||
if (s.match("^http://test.example.com")); end # $ Alert // NOT OK
|
||||
/^http:\/\/(?:.+)\.test\.example.com\//; # NOT OK
|
||||
/^http:\/\/test.example.com\/(?:.*)/; # OK
|
||||
Regexp.new("^http://test.example.com"); # NOT OK
|
||||
if (s.match("^http://test.example.com")); end # NOT OK
|
||||
|
||||
|
||||
Regexp.new(id(id(id("^http://test.example.com")))); # $ Alert // NOT OK
|
||||
Regexp.new(id(id(id("^http://test.example.com")))); # NOT OK
|
||||
|
||||
Regexp.new(`test.example.com$`); # $ Alert // NOT OK
|
||||
Regexp.new(`test.example.com$`); # NOT OK
|
||||
|
||||
hostname = '^test.example.com'; # $ Alert // NOT OK
|
||||
Regexp.new("#{hostname}$"); # $ Alert
|
||||
hostname = '^test.example.com'; # NOT OK
|
||||
Regexp.new("#{hostname}$");
|
||||
|
||||
domain = { hostname: 'test.example.com$' }; # $ Alert // NOT OK
|
||||
domain = { hostname: 'test.example.com$' }; # NOT OK
|
||||
Regexp.new(domain[:hostname]);
|
||||
|
||||
|
||||
|
||||
|
||||
convert1({ hostname: 'test.example.com$' }); # $ Alert // NOT OK
|
||||
convert1({ hostname: 'test.example.com$' }); # NOT OK
|
||||
|
||||
domains = [ { hostname: 'test.example.com$' } ]; # NOT OK - but not flagged due to limitations of TypeTracking.
|
||||
|
||||
@@ -34,18 +34,18 @@ def foo
|
||||
domains.map{ |d| convert2(d) };
|
||||
|
||||
/^(.+\.(?:example-a|example-b)\.com)\//; # NOT OK
|
||||
/^(https?:)?\/\/((service|www).)?example.com(?=$|\/)/; # $ Alert // NOT OK
|
||||
/^(http|https):\/\/www.example.com\/p\/f\//; # $ Alert // NOT OK
|
||||
/^(http:\/\/sub.example.com\/)/i; # $ Alert // NOT OK
|
||||
/^https?:\/\/api.example.com/; # $ Alert // NOT OK
|
||||
Regexp.new('^http://localhost:8000|' + "^https?://.+\\.example\\.com/"); # $ Alert // NOT OK
|
||||
/^(https?:)?\/\/((service|www).)?example.com(?=$|\/)/; # NOT OK
|
||||
/^(http|https):\/\/www.example.com\/p\/f\//; # NOT OK
|
||||
/^(http:\/\/sub.example.com\/)/i; # NOT OK
|
||||
/^https?:\/\/api.example.com/; # NOT OK
|
||||
Regexp.new('^http://localhost:8000|' + "^https?://.+\\.example\\.com/"); # NOT OK
|
||||
Regexp.new("^http[s]?:\/\/?sub1\\.sub2\\.example\\.com\/f\/(.+)"); # NOT OK
|
||||
/^https:\/\/[a-z]*.example.com$/; # $ Alert // NOT OK
|
||||
Regexp.compile('^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)'); # $ Alert // NOT OK
|
||||
/^https:\/\/[a-z]*.example.com$/; # NOT OK
|
||||
Regexp.compile('^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)'); # NOT OK
|
||||
|
||||
/^(example.dev|example.com)/; # OK
|
||||
|
||||
Regexp.new('^http://localhost:8000|' + "^https?://.+.example\\.com/"); # $ Alert // NOT OK
|
||||
Regexp.new('^http://localhost:8000|' + "^https?://.+.example\\.com/"); # NOT OK
|
||||
|
||||
primary = 'example.com$';
|
||||
Regexp.new('test.' + primary); # NOT OK, but not detected
|
||||
@@ -56,7 +56,7 @@ def foo
|
||||
|
||||
/^http:\/\/(..|...)\.example\.com\/index\.html/; # OK, wildcards are intentional
|
||||
/^http:\/\/.\.example\.com\/index\.html/; # OK, the wildcard is intentional
|
||||
/^(foo.example\.com|whatever)$/; # $ Alert // kinda OK - one disjunction doesn't even look like a hostname
|
||||
/^(foo.example\.com|whatever)$/; # kinda OK - one disjunction doesn't even look like a hostname
|
||||
end
|
||||
def id(e); return e; end
|
||||
def convert1(domain)
|
||||
@@ -78,4 +78,4 @@ class B
|
||||
end
|
||||
end
|
||||
|
||||
B.match?("^http://test.example.com") # $ Alert // NOT OK
|
||||
B.match?("^http://test.example.com") # NOT OK
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-020/IncompleteUrlSubstringSanitization.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-020/IncompleteUrlSubstringSanitization.ql
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
def test (x)
|
||||
x.index("internal") != nil; # NOT OK, but not flagged
|
||||
x.index("localhost") != nil; # NOT OK, but not flagged
|
||||
x.index("secure.com") != nil; # $ Alert // NOT OK
|
||||
x.index("secure.net") != nil; # $ Alert // NOT OK
|
||||
x.index(".secure.com") != nil; # $ Alert // NOT OK
|
||||
x.index("secure.com") != nil; # NOT OK
|
||||
x.index("secure.net") != nil; # NOT OK
|
||||
x.index(".secure.com") != nil; # NOT OK
|
||||
x.index("sub.secure.") != nil; # NOT OK, but not flagged
|
||||
x.index(".sub.secure.") != nil; # NOT OK, but not flagged
|
||||
|
||||
x.index("secure.com") === nil; # $ Alert // NOT OK
|
||||
x.index("secure.com") === 0; # $ Alert // NOT OK
|
||||
x.index("secure.com") >= 0; # $ Alert // NOT OK
|
||||
x.index("secure.com") === nil; # NOT OK
|
||||
x.index("secure.com") === 0; # NOT OK
|
||||
x.index("secure.com") >= 0; # NOT OK
|
||||
|
||||
x.start_with?("https://secure.com"); # $ Alert // NOT OK
|
||||
x.end_with?("secure.com"); # $ Alert // NOT OK
|
||||
x.start_with?("https://secure.com"); # NOT OK
|
||||
x.end_with?("secure.com"); # NOT OK
|
||||
x.end_with?(".secure.com"); # OK
|
||||
x.start_with?("secure.com/"); # OK
|
||||
x.index("secure.com/") === 0; # OK
|
||||
|
||||
x.include?("secure.com"); # $ Alert // NOT OK
|
||||
x.include?("secure.com"); # NOT OK
|
||||
|
||||
x.index("#") != nil; # OK
|
||||
x.index(":") != nil; # OK
|
||||
@@ -29,9 +29,9 @@ def test (x)
|
||||
x.index("some/path") != nil; # OK
|
||||
x.index("/index.html") != nil; # OK
|
||||
x.index(":template:") != nil; # OK
|
||||
x.index("https://secure.com") != nil; # $ Alert // NOT OK
|
||||
x.index("https://secure.com:443") != nil; # $ Alert // NOT OK
|
||||
x.index("https://secure.com/") != nil; # $ Alert // NOT OK
|
||||
x.index("https://secure.com") != nil; # NOT OK
|
||||
x.index("https://secure.com:443") != nil; # NOT OK
|
||||
x.index("https://secure.com/") != nil; # NOT OK
|
||||
|
||||
x.index(".cn") != nil; # NOT OK, but not flagged
|
||||
x.index(".jpg") != nil; # OK
|
||||
@@ -49,28 +49,28 @@ def test (x)
|
||||
x.index("tar.gz") + offset; # OK
|
||||
x.index("tar.gz") - offset; # OK
|
||||
|
||||
x.index("https://example.internal") != nil; # $ Alert // NOT OK
|
||||
x.index("https://example.internal") != nil; # NOT OK
|
||||
x.index("https://") != nil; # OK
|
||||
|
||||
x.start_with?("https://example.internal"); # $ Alert // NOT OK
|
||||
x.index('https://example.internal.org') != 0; # $ Alert // NOT OK
|
||||
x.index('https://example.internal.org') === 0; # $ Alert // NOT OK
|
||||
x.end_with?("internal.com"); # $ Alert // NOT OK
|
||||
x.start_with?("https://example.internal"); # NOT OK
|
||||
x.index('https://example.internal.org') != 0; # NOT OK
|
||||
x.index('https://example.internal.org') === 0; # NOT OK
|
||||
x.end_with?("internal.com"); # NOT OK
|
||||
x.start_with?("https://example.internal:80"); # OK
|
||||
|
||||
x.index("secure.com") != nil; # $ Alert // NOT OK
|
||||
x.index("secure.com") === nil; # $ Alert // OK
|
||||
!(x.index("secure.com") != nil); # $ Alert // OK
|
||||
!x.include?("secure.com"); # $ Alert // OK
|
||||
x.index("secure.com") != nil; # NOT OK
|
||||
x.index("secure.com") === nil; # OK
|
||||
!(x.index("secure.com") != nil); # OK
|
||||
!x.include?("secure.com"); # OK
|
||||
|
||||
if !x.include?("secure.com") # $ Alert // NOT OK
|
||||
if !x.include?("secure.com") # NOT OK
|
||||
|
||||
else
|
||||
doSomeThingWithTrustedURL(x);
|
||||
end
|
||||
|
||||
x.start_with?("https://secure.com/foo/bar"); # OK - a forward slash after the domain makes prefix checks safe.
|
||||
x.index("https://secure.com/foo/bar") >= 0 # $ Alert // NOT OK - the url can be anywhere in the string.
|
||||
x.index("https://secure.com") >= 0 # $ Alert // NOT OK
|
||||
x.index("https://secure.com/foo/bar-baz") >= 0 # $ Alert // NOT OK - the url can be anywhere in the string.
|
||||
x.index("https://secure.com/foo/bar") >= 0 # NOT OK - the url can be anywhere in the string.
|
||||
x.index("https://secure.com") >= 0 # NOT OK
|
||||
x.index("https://secure.com/foo/bar-baz") >= 0 # NOT OK - the url can be anywhere in the string.
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-020/MissingFullAnchor.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-020/MissingFullAnchor.ql
|
||||
@@ -1,17 +1,17 @@
|
||||
class Foobar
|
||||
def foo1(name) # $ Source
|
||||
raise Blabity, 'Invalid thing' if name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # $ Alert // NOT OK
|
||||
def foo1(name)
|
||||
raise Blabity, 'Invalid thing' if name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK
|
||||
end
|
||||
|
||||
def foo2(name) # $ Source
|
||||
raise Blabity, 'Invalid thing' unless name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # $ Alert // NOT OK
|
||||
def foo2(name)
|
||||
raise Blabity, 'Invalid thing' unless name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK
|
||||
end
|
||||
|
||||
def foo3(name)
|
||||
raise Blabity, 'Invalid thing' unless name !~ /\A[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*\z/ # OK
|
||||
end
|
||||
|
||||
def foo4(name) # $ Source
|
||||
raise Blabity, 'Invalid thing' unless not name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # $ Alert // NOT OK
|
||||
def foo4(name)
|
||||
raise Blabity, 'Invalid thing' unless not name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-020/MissingRegExpAnchor.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-020/MissingRegExpAnchor.ql
|
||||
@@ -1,11 +1,11 @@
|
||||
/www\.example\.com/ # $ Alert // BAD
|
||||
/www\.example\.com/ # BAD
|
||||
/^www\.example\.com$/ # BAD: uses end-of-line anchors rather than end-of-string anchors
|
||||
/\Awww\.example\.com\z/ # GOOD
|
||||
|
||||
/foo\.bar/ # GOOD
|
||||
|
||||
/https?:\/\/good\.com/ # $ Alert // BAD
|
||||
/^https?:\/\/good\.com/ # $ Alert // BAD: missing end-of-string anchor
|
||||
/https?:\/\/good\.com/ # BAD
|
||||
/^https?:\/\/good\.com/ # BAD: missing end-of-string anchor
|
||||
/(^https?:\/\/good1\.com)|(^https?:#good2\.com)/ # BAD: missing end-of-string anchor
|
||||
|
||||
/bar/ # GOOD
|
||||
@@ -16,40 +16,40 @@ foo.gsub!(/www\.example\.com/, "bar") # GOOD
|
||||
foo.sub!(/www\.example\.com/, "bar") # GOOD
|
||||
|
||||
/^a|/
|
||||
/^a|b/ # $ Alert // BAD
|
||||
/^a|b/ # BAD
|
||||
/a|^b/
|
||||
/^a|^b/
|
||||
/^a|b|c/ # $ Alert // BAD
|
||||
/^a|b|c/ # BAD
|
||||
/a|^b|c/
|
||||
/a|b|^c/
|
||||
/^a|^b|c/
|
||||
|
||||
/(^a)|b/
|
||||
/^a|(b)/ # $ Alert // BAD
|
||||
/^a|(b)/ # BAD
|
||||
/^a|(^b)/
|
||||
/^(a)|(b)/ # $ Alert // BAD
|
||||
/^(a)|(b)/ # BAD
|
||||
|
||||
|
||||
/a|b$/ # $ Alert // BAD
|
||||
/a|b$/ # BAD
|
||||
/a$|b/
|
||||
/a$|b$/
|
||||
/a|b|c$/ # $ Alert // BAD
|
||||
/a|b|c$/ # BAD
|
||||
/a|b$|c/
|
||||
/a$|b|c/
|
||||
/a|b$|c$/
|
||||
|
||||
/a|(b$)/
|
||||
/(a)|b$/ # $ Alert // BAD
|
||||
/(a)|b$/ # BAD
|
||||
/(a$)|b$/
|
||||
/(a)|(b)$/ # $ Alert // BAD
|
||||
/(a)|(b)$/ # BAD
|
||||
|
||||
/^good.com|better.com/ # $ Alert // BAD
|
||||
/^good\.com|better\.com/ # $ Alert // BAD
|
||||
/^good\\.com|better\\.com/ # $ Alert // BAD
|
||||
/^good\\\.com|better\\\.com/ # $ Alert // BAD
|
||||
/^good\\\\.com|better\\\\.com/ # $ Alert // BAD
|
||||
/^good.com|better.com/ # BAD
|
||||
/^good\.com|better\.com/ # BAD
|
||||
/^good\\.com|better\\.com/ # BAD
|
||||
/^good\\\.com|better\\\.com/ # BAD
|
||||
/^good\\\\.com|better\\\\.com/ # BAD
|
||||
|
||||
/^foo|bar|baz$/ # $ Alert // BAD
|
||||
/^foo|bar|baz$/ # BAD
|
||||
/^foo|%/ # OK
|
||||
|
||||
REGEXP = /foo/
|
||||
@@ -57,5 +57,5 @@ REGEXP.match? "http://example.com" # GOOD: the url is the text not the regexp
|
||||
REGEXP.match "http://example.com" # GOOD: the url is the text not the regexp
|
||||
"http://example.com".match? REGEXP # GOOD: the url is the text not the regexp
|
||||
"http://example.com".match REGEXP # GOOD: the url is the text not the regexp
|
||||
"some text".match? "http://example.com" # $ Alert // BAD
|
||||
"some text".match "http://example.com" # $ Alert // BAD
|
||||
"some text".match? "http://example.com" # BAD
|
||||
"some text".match "http://example.com" # BAD
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-020/OverlyLargeRange.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-020/OverlyLargeRange.ql
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
overlap1 = /^[0-93-5]$/ # $ Alert // NOT OK
|
||||
overlap1 = /^[0-93-5]$/ # NOT OK
|
||||
|
||||
overlap2 = /[A-ZA-z]/ # $ Alert // NOT OK
|
||||
overlap2 = /[A-ZA-z]/ # NOT OK
|
||||
|
||||
isEmpty = /^[z-a]$/ # $ Alert // NOT OK
|
||||
isEmpty = /^[z-a]$/ # NOT OK
|
||||
|
||||
isAscii = /^[\x00-\x7F]*$/ # OK
|
||||
|
||||
@@ -12,22 +12,22 @@ codePoints = /[^\x21-\x7E]|[\[\](){}<>\/%]/ # OK
|
||||
|
||||
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/ # OK
|
||||
|
||||
smallOverlap = /[0-9a-fA-f]/ # $ Alert // NOT OK
|
||||
smallOverlap = /[0-9a-fA-f]/ # NOT OK
|
||||
|
||||
weirdRange = /[$-`]/ # $ Alert // NOT OK
|
||||
weirdRange = /[$-`]/ # NOT OK
|
||||
|
||||
keywordOperator = /[!\~\*\/%+-<>\^|=&]/ # $ Alert // NOT OK
|
||||
keywordOperator = /[!\~\*\/%+-<>\^|=&]/ # NOT OK
|
||||
|
||||
notYoutube = /youtu\.be\/[a-z1-9.-_]+/ # $ Alert // NOT OK
|
||||
notYoutube = /youtu\.be\/[a-z1-9.-_]+/ # NOT OK
|
||||
|
||||
numberToLetter = /[7-F]/ # $ Alert // NOT OK
|
||||
numberToLetter = /[7-F]/ # NOT OK
|
||||
|
||||
overlapsWithClass1 = /[0-9\d]/ # $ Alert // NOT OK
|
||||
overlapsWithClass1 = /[0-9\d]/ # NOT OK
|
||||
|
||||
overlapsWithClass2 = /[\w,.-?:*+]/ # $ Alert // NOT OK
|
||||
overlapsWithClass2 = /[\w,.-?:*+]/ # NOT OK
|
||||
|
||||
escapes = /[\000-\037\047\134\177-\377]/n # OK - they are escapes
|
||||
|
||||
nested = /[a-z&&[^a-c]]/ # OK
|
||||
|
||||
overlapsWithNothing = /[\w_%-.]/; # $ Alert
|
||||
overlapsWithNothing = /[\w_%-.]/;
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-078/KernelOpen.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-078/KernelOpen.ql
|
||||
@@ -1,16 +1,16 @@
|
||||
class UsersController < ActionController::Base
|
||||
def create
|
||||
file = params[:file] # $ Source
|
||||
open(file) # $ Alert // BAD
|
||||
IO.read(file) # $ Alert // BAD
|
||||
IO.write(file) # $ Alert // BAD
|
||||
IO.binread(file) # $ Alert // BAD
|
||||
IO.binwrite(file) # $ Alert // BAD
|
||||
IO.foreach(file) # $ Alert // BAD
|
||||
IO.readlines(file) # $ Alert // BAD
|
||||
URI.open(file) # $ Alert // BAD
|
||||
file = params[:file]
|
||||
open(file) # BAD
|
||||
IO.read(file) # BAD
|
||||
IO.write(file) # BAD
|
||||
IO.binread(file) # BAD
|
||||
IO.binwrite(file) # BAD
|
||||
IO.foreach(file) # BAD
|
||||
IO.readlines(file) # BAD
|
||||
URI.open(file) # BAD
|
||||
|
||||
IO.read(File.join(file, "")) # $ Alert // BAD - file as first argument to File.join
|
||||
IO.read(File.join(file, "")) # BAD - file as first argument to File.join
|
||||
IO.read(File.join("", file)) # GOOD - file path is sanitised by guard
|
||||
|
||||
File.open(file).read # GOOD
|
||||
@@ -23,6 +23,6 @@ class UsersController < ActionController::Base
|
||||
IO.read(file) # GOOD - file path is sanitised by guard
|
||||
end
|
||||
|
||||
open(file) # $ Alert // BAD - sanity check to verify that file was not mistakenly marked as sanitized
|
||||
open(file) # BAD - sanity check to verify that file was not mistakenly marked as sanitized
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-078/NonConstantKernelOpen.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-078/NonConstantKernelOpen.ql
|
||||
@@ -4,18 +4,18 @@ class UsersController < ActionController::Base
|
||||
|
||||
def create
|
||||
file = params[:file]
|
||||
open(file) # $ Alert // BAD
|
||||
IO.read(file) # $ Alert // BAD
|
||||
IO.write(file) # $ Alert // BAD
|
||||
IO.binread(file) # $ Alert // BAD
|
||||
IO.binwrite(file) # $ Alert // BAD
|
||||
IO.foreach(file) # $ Alert // BAD
|
||||
IO.readlines(file) # $ Alert // BAD
|
||||
URI.open(file) # $ Alert // BAD
|
||||
open(file) # BAD
|
||||
IO.read(file) # BAD
|
||||
IO.write(file) # BAD
|
||||
IO.binread(file) # BAD
|
||||
IO.binwrite(file) # BAD
|
||||
IO.foreach(file) # BAD
|
||||
IO.readlines(file) # BAD
|
||||
URI.open(file) # BAD
|
||||
|
||||
File.open(file).read # GOOD
|
||||
|
||||
Kernel.open(file) # $ Alert // BAD
|
||||
Kernel.open(file) # BAD
|
||||
|
||||
File.open(file, "r") # GOOD
|
||||
|
||||
@@ -25,7 +25,7 @@ class UsersController < ActionController::Base
|
||||
|
||||
Kernel.open("this is #{fine}") # GOOD
|
||||
|
||||
Kernel.open("#{this_is} bad") # $ Alert // BAD
|
||||
Kernel.open("#{this_is} bad") # BAD
|
||||
|
||||
open("| #{this_is_an_explicit_command} foo bar") # GOOD
|
||||
|
||||
@@ -43,6 +43,6 @@ class UsersController < ActionController::Base
|
||||
|
||||
open.where(external: false) # GOOD - an open method is called withoout arguments
|
||||
|
||||
open(file) # $ Alert // BAD - sanity check to verify that file was not mistakenly marked as sanitized
|
||||
open(file) # BAD - sanity check to verify that file was not mistakenly marked as sanitized
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-078/UnsafeShellCommandConstruction.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-078/UnsafeShellCommandConstruction.ql
|
||||
@@ -1,5 +1,6 @@
|
||||
class Foobar
|
||||
def foo1(target) # $ Source
|
||||
IO.popen("cat #{target}", "w") # $ Alert // NOT OK - everything assumed to be imported...
|
||||
def foo1(target)
|
||||
IO.popen("cat #{target}", "w") # NOT OK - everything assumed to be imported...
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Foobar
|
||||
def foo1(target) # $ Source
|
||||
IO.popen("cat #{target}", "w") # $ Alert // NOT OK
|
||||
def foo1(target)
|
||||
IO.popen("cat #{target}", "w") # NOT OK
|
||||
end
|
||||
end
|
||||
|
||||
require 'sub/other2'
|
||||
require 'sub/other2'
|
||||
@@ -1,5 +1,5 @@
|
||||
class Foobar
|
||||
def foo1(target) # $ Source
|
||||
IO.popen("cat #{target}", "w") # $ Alert // NOT OK
|
||||
def foo1(target)
|
||||
IO.popen("cat #{target}", "w") # NOT OK
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,10 +1,10 @@
|
||||
class Foobar
|
||||
def foo1(target) # $ Source
|
||||
IO.popen("cat #{target}", "w") # $ Alert // NOT OK
|
||||
def foo1(target)
|
||||
IO.popen("cat #{target}", "w") # NOT OK
|
||||
end
|
||||
|
||||
def foo2(x) # $ Source
|
||||
format = sprintf("cat %s", x) # $ Alert // NOT OK
|
||||
def foo2(x)
|
||||
format = sprintf("cat %s", x) # NOT OK
|
||||
IO.popen(format, "w")
|
||||
end
|
||||
|
||||
@@ -12,30 +12,30 @@ class Foobar
|
||||
File.read(path) # OK
|
||||
end
|
||||
|
||||
def my_exec(cmd, command, myCmd, myCommand, innocent_file_path) # $ Source
|
||||
def my_exec(cmd, command, myCmd, myCommand, innocent_file_path)
|
||||
IO.popen("which #{cmd}", "w") # OK - the parameter is named `cmd`, so it's meant to be a command
|
||||
IO.popen("which #{command}", "w") # OK - the parameter is named `command`, so it's meant to be a command
|
||||
IO.popen("which #{myCmd}", "w") # OK - the parameter is named `myCmd`, so it's meant to be a command
|
||||
IO.popen("which #{myCommand}", "w") # OK - the parameter is named `myCommand`, so it's meant to be a command
|
||||
IO.popen("which #{innocent_file_path}", "w") # $ Alert // NOT OK - the parameter is named `innocent_file_path`, so it's not meant to be a command
|
||||
IO.popen("which #{innocent_file_path}", "w") # NOT OK - the parameter is named `innocent_file_path`, so it's not meant to be a command
|
||||
end
|
||||
|
||||
def escaped(file_path) # $ Source
|
||||
def escaped(file_path)
|
||||
IO.popen("cat #{file_path.shellescape}", "w") # OK - the parameter is escaped
|
||||
|
||||
IO.popen("cat #{file_path}", "w") # $ Alert // NOT OK - the parameter is not escaped
|
||||
IO.popen("cat #{file_path}", "w") # NOT OK - the parameter is not escaped
|
||||
end
|
||||
end
|
||||
|
||||
require File.join(File.dirname(__FILE__), 'sub', 'other')
|
||||
|
||||
class Foobar2
|
||||
def foo1(target) # $ Source
|
||||
IO.popen("cat #{target}", "w") # $ Alert // NOT OK
|
||||
def foo1(target)
|
||||
IO.popen("cat #{target}", "w") # NOT OK
|
||||
end
|
||||
|
||||
def id(x) # $ Source
|
||||
IO.popen("cat #{x}", "w") # $ Alert // NOT OK - the parameter is not a constant.
|
||||
def id(x)
|
||||
IO.popen("cat #{x}", "w") # NOT OK - the parameter is not a constant.
|
||||
return x
|
||||
end
|
||||
|
||||
@@ -44,27 +44,27 @@ class Foobar2
|
||||
end
|
||||
|
||||
# class methods
|
||||
def self.foo(target) # $ Source
|
||||
IO.popen("cat #{target}", "w") # $ Alert // NOT OK
|
||||
def self.foo(target)
|
||||
IO.popen("cat #{target}", "w") # NOT OK
|
||||
end
|
||||
|
||||
def arrayJoin(x) # $ Source
|
||||
IO.popen(x.join(' '), "w") # $ Alert // NOT OK
|
||||
def arrayJoin(x)
|
||||
IO.popen(x.join(' '), "w") # NOT OK
|
||||
|
||||
IO.popen(["foo", "bar", x].join(' '), "w") # $ Alert // NOT OK
|
||||
IO.popen(["foo", "bar", x].join(' '), "w") # NOT OK
|
||||
end
|
||||
|
||||
def string_concat(x) # $ Source
|
||||
IO.popen("cat " + x, "w") # $ Alert // NOT OK
|
||||
def string_concat(x)
|
||||
IO.popen("cat " + x, "w") # NOT OK
|
||||
end
|
||||
|
||||
def array_taint (x, y) # $ Source
|
||||
def array_taint (x, y)
|
||||
arr = ["cat"]
|
||||
arr.push(x)
|
||||
IO.popen(arr.join(' '), "w") # $ Alert // NOT OK
|
||||
IO.popen(arr.join(' '), "w") # NOT OK
|
||||
|
||||
arr2 = ["cat"]
|
||||
arr2 << y
|
||||
IO.popen(arr.join(' '), "w") # $ Alert // NOT OK
|
||||
IO.popen(arr.join(' '), "w") # NOT OK
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-079/ReflectedXSS.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-079/ReflectedXSS.ql
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-079/StoredXSS.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-079/StoredXSS.ql
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-079/UnsafeHtmlConstruction.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-079/UnsafeHtmlConstruction.ql
|
||||
@@ -6,34 +6,34 @@ class BarsController < ApplicationController
|
||||
end
|
||||
|
||||
def user_name
|
||||
return params[:user_name] # $ Source[rb/reflected-xss]
|
||||
return params[:user_name]
|
||||
end
|
||||
|
||||
def user_name_memo
|
||||
@user_name ||= params[:user_name] # $ Source[rb/reflected-xss]
|
||||
@user_name ||= params[:user_name]
|
||||
end
|
||||
|
||||
def show
|
||||
@user_website = params[:website] # $ Source[rb/reflected-xss]
|
||||
dt = params[:text] # $ Source[rb/reflected-xss]
|
||||
@user_website = params[:website]
|
||||
dt = params[:text]
|
||||
@instance_text = dt
|
||||
@safe_foo = params[:text]
|
||||
@safe_foo = "safe_foo"
|
||||
@html_escaped = ERB::Util.html_escape(params[:text])
|
||||
@header_escaped = ERB::Util.html_escape(cookies[:foo]) # OK - cookies not controllable by 3rd party
|
||||
response.header["content-type"] = params[:content_type] # $ Alert[rb/reflected-xss]
|
||||
response.header["content-type"] = params[:content_type]
|
||||
response.header["x-customer-header"] = params[:bar] # OK - header not relevant to XSS
|
||||
render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" }
|
||||
end
|
||||
|
||||
def make_safe_html
|
||||
str = params[:user_name] # $ Source[rb/reflected-xss]
|
||||
str.html_safe # $ Alert[rb/reflected-xss]
|
||||
str = params[:user_name]
|
||||
str.html_safe
|
||||
|
||||
translate("welcome", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - translate preserves taint
|
||||
t("welcome", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - t is an alias of translate
|
||||
translate("welcome", name: params[:user_name]).html_safe # NOT OK - translate preserves taint
|
||||
t("welcome", name: params[:user_name]).html_safe # NOT OK - t is an alias of translate
|
||||
t("welcome_html", name: params[:user_name]).html_safe # OK - t escapes html when key ends in _html
|
||||
I18n.t("welcome_html", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - I18n.t does not escape html
|
||||
I18n.translate("welcome_html", name: params[:user_name]).html_safe # $ Alert[rb/reflected-xss] // NOT OK - alias
|
||||
I18n.t("welcome_html", name: params[:user_name]).html_safe # NOT OK - I18n.t does not escape html
|
||||
I18n.translate("welcome_html", name: params[:user_name]).html_safe # NOT OK - alias
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,7 +5,7 @@ class StoresController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
dt = File.read("foo.txt") # $ Source[rb/stored-xss]
|
||||
dt = File.read("foo.txt")
|
||||
@instance_text = dt
|
||||
@user = User.find 1
|
||||
@safe_user_handle = ERB::Util.html_escape(@user.handle)
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<%= raw @display_text %>
|
||||
|
||||
<%# BAD: A local rendered raw as a local variable %>
|
||||
<%= raw display_text %> <%# $ Alert[rb/reflected-xss], Alert[rb/stored-xss] %>
|
||||
<%= raw display_text %>
|
||||
|
||||
<%# BAD: A local rendered raw via the local_assigns hash %>
|
||||
<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/reflected-xss], Alert[rb/stored-xss] %>
|
||||
<%= raw local_assigns[:display_text] %>
|
||||
|
||||
<%# GOOD: A local rendered with default escaping via the local_assigns hash %>
|
||||
<%= local_assigns[:display_text] %>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<%# BAD: An instance variable rendered without escaping %>
|
||||
<a href="<%= raw @user_website %>">website</a> <%# $ Alert[rb/reflected-xss] %>
|
||||
<a href="<%= raw @user_website %>">website</a>
|
||||
|
||||
<%# BAD: A local rendered raw as a local variable %>
|
||||
<%= raw display_text %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= raw display_text %>
|
||||
|
||||
<%# BAD: A local rendered raw via the local_assigns hash %>
|
||||
<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= raw local_assigns[:display_text] %>
|
||||
|
||||
<% key = :display_text %>
|
||||
<%# BAD: A local rendered raw via the locals_assigns hash %>
|
||||
<%= raw local_assigns[key] %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= raw local_assigns[key] %>
|
||||
|
||||
<ul>
|
||||
<% for key in [:display_text, :safe_text] do %>
|
||||
<%# BAD: A local rendered raw via the locals hash %>
|
||||
<li><%= raw local_assigns[key] %></li> <%# $ Alert[rb/reflected-xss] %>
|
||||
<li><%= raw local_assigns[key] %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
@@ -32,28 +32,28 @@
|
||||
|
||||
<%# BAD: html_safe marks string as not requiring HTML escaping %>
|
||||
<%=
|
||||
display_text.html_safe <%# $ Alert[rb/reflected-xss] %>
|
||||
display_text.html_safe
|
||||
%>
|
||||
|
||||
<%# BAD: html_safe marks string as not requiring HTML escaping %>
|
||||
<%=
|
||||
@instance_text.html_safe <%# $ Alert[rb/reflected-xss] %>
|
||||
@instance_text.html_safe
|
||||
%>
|
||||
|
||||
<%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %>
|
||||
|
||||
<%# BAD: user_name is a helper method that returns unsanitized user-input %>
|
||||
<%= user_name.html_safe %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= user_name.html_safe %>
|
||||
|
||||
<%# BAD: user_name_memo is a helper method that returns unsanitized user-input %>
|
||||
<%# TODO: we miss this because the return value from user_name_memo is not properly linked to this call %>
|
||||
<%= user_name_memo.html_safe %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= user_name_memo.html_safe %>
|
||||
|
||||
<%# BAD: unsanitized user-input should not be passed to link_to as the URL %>
|
||||
<%= link_to "user website", params[:website] %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= link_to "user website", params[:website] %>
|
||||
|
||||
<%# BAD: unsanitized user-input should not be passed to link_to as the URL %>
|
||||
<%= link_to params[:website], class: "user-link" do %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= link_to params[:website], class: "user-link" do %>
|
||||
user website
|
||||
<% end %>
|
||||
|
||||
@@ -70,20 +70,20 @@
|
||||
%>
|
||||
|
||||
<%# BAD: simple_format called with sanitize: false %>
|
||||
<%= simple_format(params[:comment], sanitize: false) %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= simple_format(params[:comment], sanitize: false) %>
|
||||
|
||||
<%# BAD: javasript_include_tag called with remote input %>
|
||||
<%= javascript_include_tag params[:url] %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= javascript_include_tag params[:url] %>
|
||||
|
||||
<%# GOOD: input is sanitized %>
|
||||
<%= sanitize(params[:comment]).html_safe %>
|
||||
|
||||
<%# BAD: A local rendered raw as a local variable %>
|
||||
<%== display_text %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%== display_text %>
|
||||
|
||||
<%# BAD: translate preserves taint %>
|
||||
<%= raw translate("welcome", name: display_text) %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= raw t("welcome", name: display_text) %> <%# $ Alert[rb/reflected-xss] %>
|
||||
<%= raw translate("welcome", name: display_text) %>
|
||||
<%= raw t("welcome", name: display_text) %>
|
||||
|
||||
<%# GOOD: translate sanitizes for html keys %>
|
||||
<%= raw t("welcome1.html", name: display_text) %>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<%# BAD: A local rendered raw as a local variable %>
|
||||
<%= raw display_text %> <%# $ Alert[rb/stored-xss] %>
|
||||
<%= raw display_text %>
|
||||
|
||||
<%# BAD: A local rendered raw via the local_assigns hash %>
|
||||
<%= raw local_assigns[:display_text] %> <%# $ Alert[rb/stored-xss] %>
|
||||
<%= raw local_assigns[:display_text] %>
|
||||
|
||||
<% key = :display_text %>
|
||||
<%# BAD: A local rendered raw via the locals_assigns hash %>
|
||||
<%= raw local_assigns[key] %> <%# $ Alert[rb/stored-xss] %>
|
||||
<%= raw local_assigns[key] %>
|
||||
|
||||
<ul>
|
||||
<% for key in [:display_text, :safe_text] do %>
|
||||
<%# BAD: A local rendered raw via the locals hash %>
|
||||
<li><%= raw local_assigns[key] %></li> <%# $ Alert[rb/stored-xss] %>
|
||||
<li><%= raw local_assigns[key] %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
|
||||
<%# BAD: html_safe marks string as not requiring HTML escaping %>
|
||||
<%=
|
||||
display_text.html_safe <%# $ Alert[rb/stored-xss] %>
|
||||
display_text.html_safe
|
||||
%>
|
||||
|
||||
<%# BAD: html_safe marks string as not requiring HTML escaping %>
|
||||
<%=
|
||||
@instance_text.html_safe <%# $ Alert[rb/stored-xss] %>
|
||||
@instance_text.html_safe
|
||||
%>
|
||||
|
||||
<%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %>
|
||||
@@ -43,7 +43,7 @@
|
||||
<%= user_name_handle.html_safe %>
|
||||
|
||||
<%# BAD: Direct to a database value without escaping %>
|
||||
<%= @user.handle.html_safe %> <%# $ Alert[rb/stored-xss] %>
|
||||
<%= @user.handle.html_safe %>
|
||||
|
||||
<%# BAD: Indirect to a database value without escaping %>
|
||||
<%= @user.raw_name.html_safe %>
|
||||
@@ -60,7 +60,7 @@
|
||||
<%# BAD: Direct to a database value without escaping %>
|
||||
<%=
|
||||
some_user = User.find 1
|
||||
some_user.handle.html_safe <%# $ Alert[rb/stored-xss] %>
|
||||
some_user.handle.html_safe
|
||||
%>
|
||||
|
||||
<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %>
|
||||
@@ -83,7 +83,7 @@
|
||||
|
||||
<%# BAD: Kernel.sprintf is a taint-step %>
|
||||
<%=
|
||||
sprintf("%s", @user.handle).html_safe <%# $ Alert[rb/stored-xss] %>
|
||||
sprintf("%s", @user.handle).html_safe
|
||||
%>
|
||||
|
||||
<%# GOOD: The `foo.bar.baz` is not recognized as a source %>
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
class Foobar
|
||||
def create_user_description(name) # $ Source[rb/html-constructed-from-input]
|
||||
"<h2>#{name}</h2>".html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the parameter is not escaped
|
||||
def create_user_description(name)
|
||||
"<h2>#{name}</h2>".html_safe # NOT OK - the parameter is not escaped
|
||||
|
||||
# escape
|
||||
"<h2>#{ERB::Util.html_escape(name)}</h2>".html_safe # OK - the parameter is escaped
|
||||
end
|
||||
|
||||
def string_like_literal name # $ Source[rb/html-constructed-from-input]
|
||||
def string_like_literal name
|
||||
h = <<-HTML
|
||||
<h2>#{name}</h2> # $ Alert[rb/html-constructed-from-input]
|
||||
<h2>#{name}</h2>
|
||||
HTML
|
||||
h.html_safe # NOT OK - the parameter is not escaped
|
||||
end
|
||||
|
||||
def sprintf_use name # $ Source[rb/html-constructed-from-input]
|
||||
sprintf("<h2>%s</h2>", name).html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the parameter is not escaped
|
||||
def sprintf_use name
|
||||
sprintf("<h2>%s</h2>", name).html_safe # NOT OK - the parameter is not escaped
|
||||
|
||||
# escape
|
||||
sprintf("<h2>%s</h2>", ERB::Util.html_escape(name)).html_safe # OK - the parameter is escaped
|
||||
end
|
||||
|
||||
def create_user_description2(name) # $ Source[rb/html-constructed-from-input]
|
||||
"<h2>#{name}</h2>".html_safe # $ Alert[rb/html-constructed-from-input] // NOT OK - the value is not necessarily HTML safe
|
||||
def create_user_description2(name)
|
||||
"<h2>#{name}</h2>".html_safe # NOT OK - the value is not necessarily HTML safe
|
||||
|
||||
if name.html_safe?
|
||||
"<h2>#{name}</h2>".html_safe # OK - value is marked as being HTML safe
|
||||
|
||||
@@ -7,13 +7,13 @@ class User < ApplicationRecord
|
||||
|
||||
def self.authenticate(name, pass)
|
||||
# BAD: possible untrusted input interpolated into SQL fragment
|
||||
find(:first, :conditions => "name='#{name}' and pass='#{pass}'") # $ Alert
|
||||
find(:first, :conditions => "name='#{name}' and pass='#{pass}'")
|
||||
# BAD: interpolation in array argument
|
||||
find(:first, conditions: ["name='#{name}' and pass='#{pass}'"]) # $ Alert
|
||||
find(:first, conditions: ["name='#{name}' and pass='#{pass}'"])
|
||||
# GOOD: using SQL parameters
|
||||
find(:first, conditions: ["name = ? and pass = ?", name, pass])
|
||||
# BAD: interpolation with flow
|
||||
conds = "name=#{name}" # $ Alert
|
||||
conds = "name=#{name}"
|
||||
find(:first, conditions: conds)
|
||||
end
|
||||
|
||||
@@ -27,7 +27,7 @@ class Admin < User
|
||||
def self.delete_by(condition = nil)
|
||||
# BAD: `delete_by overrides an ActiveRecord method, but doesn't perform
|
||||
# any validation before passing its arguments on to another ActiveRecord method
|
||||
destroy_by(condition) # $ Alert
|
||||
destroy_by(condition)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,64 +39,64 @@ class FooController < ActionController::Base
|
||||
def some_request_handler
|
||||
# BAD: executes `SELECT AVG(#{params[:column]}) FROM "users"`
|
||||
# where `params[:column]` is unsanitized
|
||||
User.calculate(:average, params[:column]) # $ Alert
|
||||
User.calculate(:average, params[:column])
|
||||
|
||||
# BAD: executes `SELECT MAX(#{params[:column]}) FROM "users"`
|
||||
# where `params[:column]` is unsanitized
|
||||
User.maximum(params[:column]) # $ Alert
|
||||
User.maximum(params[:column])
|
||||
|
||||
# BAD: executes `DELETE FROM "users" WHERE (id = '#{params[:id]}')`
|
||||
# where `params[:id]` is unsanitized
|
||||
User.delete_by("id = '#{params[:id]}'") # $ Alert
|
||||
User.delete_by("id = '#{params[:id]}'")
|
||||
|
||||
# BAD: executes `DELETE FROM "users" WHERE (id = '#{params[:id]}')`
|
||||
# where `params[:id]` is unsanitized
|
||||
# (in Rails < 4.0)
|
||||
User.delete_all("id = '#{params[:id]}'") # $ Alert
|
||||
User.delete_all("id = '#{params[:id]}'")
|
||||
|
||||
# BAD: executes `SELECT "users".* FROM "users" WHERE (id = '#{params[:id]}')`
|
||||
# where `params[:id]` is unsanitized
|
||||
User.destroy_by(["id = '#{params[:id]}'"]) # $ Alert
|
||||
User.destroy_by(["id = '#{params[:id]}'"])
|
||||
|
||||
# BAD: executes `SELECT "users".* FROM "users" WHERE (id = '#{params[:id]}')`
|
||||
# where `params[:id]` is unsanitized
|
||||
# (in Rails < 4.0)
|
||||
User.destroy_all(["id = '#{params[:id]}'"]) # $ Alert
|
||||
User.destroy_all(["id = '#{params[:id]}'"])
|
||||
|
||||
# BAD: executes `SELECT "users".* FROM "users" WHERE id BETWEEN '#{params[:min_id]}' AND 100000`
|
||||
# where `params[:min_id]` is unsanitized
|
||||
User.where(<<-SQL, MAX_USER_ID) # $ Alert
|
||||
id BETWEEN '#{params[:min_id]}' AND ? # $ Source
|
||||
User.where(<<-SQL, MAX_USER_ID)
|
||||
id BETWEEN '#{params[:min_id]}' AND ?
|
||||
SQL
|
||||
|
||||
# BAD: chained method case
|
||||
# executes `SELECT "users".* FROM "users" WHERE (NOT (user_id = 'params[:id]'))`
|
||||
# where `params[:id]` is unsanitized
|
||||
User.where.not("user.id = '#{params[:id]}'") # $ Alert
|
||||
User.where.not("user.id = '#{params[:id]}'")
|
||||
|
||||
User.authenticate(params[:name], params[:pass]) # $ Source
|
||||
User.authenticate(params[:name], params[:pass])
|
||||
|
||||
# BAD: executes `SELECT "users".* FROM "users" WHERE (id = '#{params[:id]}')` LIMIT 1
|
||||
# where `params[:id]` is unsanitized
|
||||
User.find_or_initialize_by("id = '#{params[:id]}'") # $ Alert
|
||||
User.find_or_initialize_by("id = '#{params[:id]}'")
|
||||
|
||||
user = User.first
|
||||
# BAD: executes `SELECT "users".* FROM "users" WHERE id = 1 LIMIT 1 #{params[:lock]}`
|
||||
# where `params[:lock]` is unsanitized
|
||||
user.reload(lock: params[:lock]) # $ Alert
|
||||
user.reload(lock: params[:lock])
|
||||
|
||||
# BAD: executes `SELECT #{params[:column]} FROM "users"`
|
||||
# where `params[:column]` is unsanitized
|
||||
User.select(params[:column]) # $ Alert
|
||||
User.reselect(params[:column]) # $ Alert
|
||||
User.select(params[:column])
|
||||
User.reselect(params[:column])
|
||||
|
||||
# BAD: executes `SELECT "users".* FROM "users" WHERE (#{params[:condition]})`
|
||||
# where `params[:condition]` is unsanitized
|
||||
User.rewhere(params[:condition]) # $ Alert
|
||||
User.rewhere(params[:condition])
|
||||
|
||||
# BAD: executes `UPDATE "users" SET #{params[:fields]}`
|
||||
# where `params[:fields]` is unsanitized
|
||||
User.update_all(params[:fields]) # $ Alert
|
||||
User.update_all(params[:fields])
|
||||
|
||||
# GOOD -- `update_all` sanitizes its bind variable arguments
|
||||
User.find_by(name: params[:user_name])
|
||||
@@ -104,41 +104,41 @@ class FooController < ActionController::Base
|
||||
|
||||
# BAD -- `update_all` does not sanitize its query (array arg)
|
||||
User.find_by(name: params[:user_name])
|
||||
.update_all(["name = '#{params[:new_user_name]}'"]) # $ Alert
|
||||
.update_all(["name = '#{params[:new_user_name]}'"])
|
||||
|
||||
# BAD -- `update_all` does not sanitize its query (string arg)
|
||||
User.find_by(name: params[:user_name])
|
||||
.update_all("name = '#{params[:new_user_name]}'") # $ Alert
|
||||
.update_all("name = '#{params[:new_user_name]}'")
|
||||
|
||||
User.reorder(params[:direction]) # $ Alert
|
||||
User.reorder(params[:direction])
|
||||
|
||||
User.select('a','b', params[:column]) # $ Alert
|
||||
User.reselect('a','b', params[:column]) # $ Alert
|
||||
User.order('a ASC', "b #{params[:direction]}") # $ Alert
|
||||
User.reorder('a ASC', "b #{params[:direction]}") # $ Alert
|
||||
User.group('a', params[:column]) # $ Alert
|
||||
User.pluck('a', params[:column]) # $ Alert
|
||||
User.joins(:a, params[:column]) # $ Alert
|
||||
User.select('a','b', params[:column])
|
||||
User.reselect('a','b', params[:column])
|
||||
User.order('a ASC', "b #{params[:direction]}")
|
||||
User.reorder('a ASC', "b #{params[:direction]}")
|
||||
User.group('a', params[:column])
|
||||
User.pluck('a', params[:column])
|
||||
User.joins(:a, params[:column])
|
||||
|
||||
User.count_by_sql(params[:custom_sql_query]) # $ Alert
|
||||
User.count_by_sql(params[:custom_sql_query])
|
||||
|
||||
# BAD: executes `SELECT users.* FROM #{params[:tab]}`
|
||||
# where `params[:tab]` is unsanitized
|
||||
User.all.from(params[:tab]) # $ Alert
|
||||
User.all.from(params[:tab])
|
||||
# BAD: executes `SELECT "users".* FROM (SELECT "users".* FROM "users") #{params[:sq]}
|
||||
User.all.from(User.all, params[:sq]) # $ Alert
|
||||
User.all.from(User.all, params[:sq])
|
||||
end
|
||||
end
|
||||
|
||||
class BarController < ApplicationController
|
||||
def some_other_request_handler
|
||||
ps = params # $ Source
|
||||
ps = params
|
||||
uid = ps[:id]
|
||||
uidEq = "= '#{uid}'"
|
||||
|
||||
# BAD: executes `DELETE FROM "users" WHERE (id = #{uid})`
|
||||
# where `uid` is unsantized
|
||||
User.delete_by("id " + uidEq) # $ Alert
|
||||
User.delete_by("id " + uidEq)
|
||||
end
|
||||
|
||||
def safe_paths
|
||||
@@ -171,7 +171,7 @@ end
|
||||
|
||||
class BazController < BarController
|
||||
def yet_another_handler
|
||||
Admin.delete_by(params[:admin_condition]) # $ Alert, Source
|
||||
Admin.delete_by(params[:admin_condition])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -185,7 +185,7 @@ class AnnotatedController < ActionController::Base
|
||||
def unsafe_action
|
||||
name = params[:user_name]
|
||||
# BAD: user input passed into annotations are vulnerable to SQLi
|
||||
users = User.annotate("this is an unsafe annotation:#{params[:comment]}").find_by(user_name: name) # $ Alert
|
||||
users = User.annotate("this is an unsafe annotation:#{params[:comment]}").find_by(user_name: name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -198,27 +198,27 @@ class RegressionController < ActionController::Base
|
||||
def index
|
||||
my_params = permitted_params
|
||||
query = "SELECT * FROM users WHERE id = #{my_params[:user_id]}"
|
||||
result = Regression.find_by_sql(query) # $ Alert
|
||||
result = Regression.find_by_sql(query)
|
||||
end
|
||||
|
||||
|
||||
def permitted_params
|
||||
params.require(:my_key).permit(:id, :user_id, :my_type) # $ Source
|
||||
params.require(:my_key).permit(:id, :user_id, :my_type)
|
||||
end
|
||||
|
||||
def show
|
||||
ActiveRecord::Base.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}") # $ Alert
|
||||
Regression.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}") # $ Alert
|
||||
ActiveRecord::Base.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}")
|
||||
Regression.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}")
|
||||
end
|
||||
end
|
||||
|
||||
class User
|
||||
scope :with_role, ->(role) { where("role = #{role}") } # $ Alert
|
||||
scope :with_role, ->(role) { where("role = #{role}") }
|
||||
end
|
||||
|
||||
class UsersController < ActionController::Base
|
||||
def index
|
||||
# BAD: user input passed to scope which uses it without sanitization.
|
||||
@users = User.with_role(params[:role]) # $ Source
|
||||
@users = User.with_role(params[:role])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
class PotatoController < ActionController::Base
|
||||
def unsafe_action
|
||||
name = params[:user_name] # $ Source
|
||||
name = params[:user_name]
|
||||
# BAD: SQL statement constructed from user input
|
||||
sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") # $ Alert
|
||||
sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}") # $ Alert
|
||||
sql = Arel.sql("SELECT * FROM users WHERE name = #{name}")
|
||||
sql = Arel::Nodes::SqlLiteral.new("SELECT * FROM users WHERE name = #{name}")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,7 +3,7 @@ class FooController < ActionController::Base
|
||||
def some_request_handler
|
||||
# A string tainted by user input is inserted into a query
|
||||
# (i.e a remote flow source)
|
||||
name = params[:name] # $ Source
|
||||
name = params[:name]
|
||||
|
||||
# Establish a connection to a PostgreSQL database
|
||||
conn = PG::Connection.open(:dbname => 'postgresql', :user => 'user', :password => 'pass', :host => 'localhost', :port => '5432')
|
||||
@@ -11,14 +11,14 @@ class FooController < ActionController::Base
|
||||
# .exec() and .async_exec()
|
||||
# BAD: SQL statement constructed from user input
|
||||
qry1 = "SELECT * FROM users WHERE username = '#{name}';"
|
||||
conn.exec(qry1) # $ Alert
|
||||
conn.async_exec(qry1) # $ Alert
|
||||
conn.exec(qry1)
|
||||
conn.async_exec(qry1)
|
||||
|
||||
# .exec_params() and .async_exec_params()
|
||||
# BAD: SQL statement constructed from user input
|
||||
qry2 = "SELECT * FROM users WHERE username = '#{name}';"
|
||||
conn.exec_params(qry2) # $ Alert
|
||||
conn.async_exec_params(qry2) # $ Alert
|
||||
conn.exec_params(qry2)
|
||||
conn.async_exec_params(qry2)
|
||||
|
||||
# .exec_params() and .async_exec_params()
|
||||
# GOOD: SQL statement constructed from sanitized user input
|
||||
@@ -29,7 +29,7 @@ class FooController < ActionController::Base
|
||||
# .prepare() and .exec_prepared()
|
||||
# BAD: SQL statement constructed from user input
|
||||
qry3 = "SELECT * FROM users WHERE username = '#{name}';"
|
||||
conn.prepare("query_1", qry3) # $ Alert
|
||||
conn.prepare("query_1", qry3)
|
||||
conn.exec_prepared('query_1')
|
||||
|
||||
# .prepare() and .exec_prepared()
|
||||
@@ -41,7 +41,7 @@ class FooController < ActionController::Base
|
||||
# .prepare() and .exec_prepared()
|
||||
# NOT EXECUTED: SQL statement constructed from user input but not executed
|
||||
qry3 = "SELECT * FROM users WHERE username = '#{name}';"
|
||||
conn.prepare("query_3", qry3) # $ Alert
|
||||
conn.prepare("query_3", qry3)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-089/SqlInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-089/SqlInjection.ql
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-094/UnsafeCodeConstruction.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-094/UnsafeCodeConstruction.ql
|
||||
@@ -1,16 +1,16 @@
|
||||
class Foobar
|
||||
def foo1(target) # $ Source
|
||||
eval("foo = #{target}") # $ Alert // NOT OK
|
||||
def foo1(target)
|
||||
eval("foo = #{target}") # NOT OK
|
||||
end
|
||||
|
||||
# sprintf
|
||||
def foo2(x) # $ Source
|
||||
eval(sprintf("foo = %s", x)) # $ Alert // NOT OK
|
||||
def foo2(x)
|
||||
eval(sprintf("foo = %s", x)) # NOT OK
|
||||
end
|
||||
|
||||
# String#%
|
||||
def foo3(x) # $ Source
|
||||
eval("foo = %{foo}" % {foo: x}) # $ Alert // NOT OK
|
||||
def foo3(x)
|
||||
eval("foo = %{foo}" % {foo: x}) # NOT OK
|
||||
end
|
||||
|
||||
def indirect_eval(x)
|
||||
@@ -25,42 +25,42 @@ class Foobar
|
||||
eval("def \n #{code} \n end") # OK - parameter is named code
|
||||
end
|
||||
|
||||
def joinStuff(my_arr) # $ Source
|
||||
eval(my_arr.join("\n")) # $ Alert // NOT OK
|
||||
def joinStuff(my_arr)
|
||||
eval(my_arr.join("\n")) # NOT OK
|
||||
end
|
||||
|
||||
def joinWithElemt(x) # $ Source
|
||||
def joinWithElemt(x)
|
||||
arr = [x, "foobar"]
|
||||
eval(arr.join("\n")) # $ Alert // NOT OK
|
||||
eval(arr.join("\n")) # NOT OK
|
||||
end
|
||||
|
||||
def pushArr(x, y) # $ Source
|
||||
def pushArr(x, y)
|
||||
arr = []
|
||||
arr.push(x)
|
||||
eval(arr.join("\n")) # $ Alert // NOT OK
|
||||
eval(arr.join("\n")) # NOT OK
|
||||
|
||||
arr2 = []
|
||||
arr2 << y
|
||||
eval(arr.join("\n")) # $ Alert // NOT OK
|
||||
eval(arr.join("\n")) # NOT OK
|
||||
end
|
||||
|
||||
def hereDoc(x) # $ Source
|
||||
def hereDoc(x)
|
||||
foo = <<~HERE
|
||||
#{x} # $ Alert
|
||||
#{x}
|
||||
HERE
|
||||
eval(foo) # NOT OK
|
||||
end
|
||||
|
||||
def string_concat(x) # $ Source
|
||||
foo = "foo = " + x # $ Alert
|
||||
def string_concat(x)
|
||||
foo = "foo = " + x
|
||||
eval(foo) # NOT OK
|
||||
end
|
||||
|
||||
def join_indirect(x, y) # $ Source
|
||||
def join_indirect(x, y)
|
||||
arr = Array(x)
|
||||
eval(arr.join(" ")) # $ Alert // NOT OK
|
||||
eval(arr.join(" ")) # NOT OK
|
||||
|
||||
arr2 = [Array(["foo = ", y]).join(" ")]
|
||||
eval(arr2.join("\n")) # $ Alert // NOT OK
|
||||
eval(arr2.join("\n")) # NOT OK
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-116/BadTagFilter.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-116/BadTagFilter.ql
|
||||
@@ -1,22 +1,22 @@
|
||||
filters = [
|
||||
/<script.*?>.*?<\/script>/i, # $ Alert // NOT OK - doesn't match newlines or `</script >`
|
||||
/<script.*?>.*?<\/script>/im, # $ Alert // NOT OK - doesn't match `</script >`
|
||||
/<script.*?>.*?<\/script>/i, # NOT OK - doesn't match newlines or `</script >`
|
||||
/<script.*?>.*?<\/script>/im, # NOT OK - doesn't match `</script >`
|
||||
/<script.*?>.*?<\/script[^>]*>/im, # OK
|
||||
/<!--.*-->/im, # OK - we don't care regexps that only match comments
|
||||
/<!--.*--!?>/im, # OK
|
||||
/<!--.*--!?>/i, # $ Alert // NOT OK, does not match newlines
|
||||
/<script.*?>(.|\s)*?<\/script[^>]*>/i, # $ Alert // NOT OK - doesn't match inside the script tag
|
||||
/<script[^>]*?>.*?<\/script[^>]*>/i, # $ Alert // NOT OK - doesn't match newlines inside the content
|
||||
/<script(\s|\w|=|")*?>.*?<\/script[^>]*>/im, # $ Alert // NOT OK - does not match single quotes for attribute values
|
||||
/<script(\s|\w|=|')*?>.*?<\/script[^>]*>/im, # $ Alert // NOT OK - does not match double quotes for attribute values
|
||||
/<script( |\n|\w|=|'|")*?>.*?<\/script[^>]*>/im, # $ Alert // NOT OK - does not match tabs between attributes
|
||||
/<script.*?>.*?<\/script[^>]*>/m, # $ Alert // NOT OK - does not match uppercase SCRIPT tags
|
||||
/<(script|SCRIPT).*?>.*?<\/(script|SCRIPT)[^>]*>/m, # $ Alert // NOT OK - does not match mixed case script tags
|
||||
/<script[^>]*?>[\s\S]*?<\/script.*>/i, # $ Alert // NOT OK - doesn't match newlines in the end tag
|
||||
/<!--.*--!?>/i, # NOT OK, does not match newlines
|
||||
/<script.*?>(.|\s)*?<\/script[^>]*>/i, # NOT OK - doesn't match inside the script tag
|
||||
/<script[^>]*?>.*?<\/script[^>]*>/i, # NOT OK - doesn't match newlines inside the content
|
||||
/<script(\s|\w|=|")*?>.*?<\/script[^>]*>/im, # NOT OK - does not match single quotes for attribute values
|
||||
/<script(\s|\w|=|')*?>.*?<\/script[^>]*>/im, # NOT OK - does not match double quotes for attribute values
|
||||
/<script( |\n|\w|=|'|")*?>.*?<\/script[^>]*>/im, # NOT OK - does not match tabs between attributes
|
||||
/<script.*?>.*?<\/script[^>]*>/m, # NOT OK - does not match uppercase SCRIPT tags
|
||||
/<(script|SCRIPT).*?>.*?<\/(script|SCRIPT)[^>]*>/m, # NOT OK - does not match mixed case script tags
|
||||
/<script[^>]*?>[\s\S]*?<\/script.*>/i, # NOT OK - doesn't match newlines in the end tag
|
||||
/<script[^>]*?>[\s\S]*?<\/script[^>]*?>/i, # OK
|
||||
/<script\b[^>]*>([\s\S]*?)<\/script>/gi, # $ Alert // NOT OK - too strict matching on the end tag
|
||||
/<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>/, # $ Alert // NOT OK - doesn't match comments with the right capture groups
|
||||
/<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/, # $ Alert // NOT OK - capture groups
|
||||
/<script\b[^>]*>([\s\S]*?)<\/script>/gi, # NOT OK - too strict matching on the end tag
|
||||
/<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>/, # NOT OK - doesn't match comments with the right capture groups
|
||||
/<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/, # NOT OK - capture groups
|
||||
]
|
||||
|
||||
doFilters(filters)
|
||||
doFilters(filters)
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-116/IncompleteSanitization.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-116/IncompleteSanitization.ql
|
||||
@@ -1,91 +1,91 @@
|
||||
|
||||
def bad1(s)
|
||||
s.sub "'", "" # $ Alert // NOT OK
|
||||
s.sub! "'", "" # $ Alert // NOT OK
|
||||
s.sub "'", "" # NOT OK
|
||||
s.sub! "'", "" # NOT OK
|
||||
end
|
||||
|
||||
def bad2(s)
|
||||
s.sub /'/, "" # $ Alert // NOT OK
|
||||
s.sub! /'/, "" # $ Alert // NOT OK
|
||||
s.sub /'/, "" # NOT OK
|
||||
s.sub! /'/, "" # NOT OK
|
||||
end
|
||||
|
||||
def bad3(s1, s2, s3)
|
||||
s1.gsub /'/, "\\'" # $ Alert // NOT OK
|
||||
s1.gsub /'/, '\\\'' # $ Alert // NOT OK
|
||||
s2.gsub! /'/, "\\'" # $ Alert // NOT OK
|
||||
s3.gsub! /'/, '\\\'' # $ Alert // NOT OK
|
||||
s1.gsub /'/, "\\'" # NOT OK
|
||||
s1.gsub /'/, '\\\'' # NOT OK
|
||||
s2.gsub! /'/, "\\'" # NOT OK
|
||||
s3.gsub! /'/, '\\\'' # NOT OK
|
||||
end
|
||||
|
||||
def bad4(s1, s2, s3)
|
||||
s1.gsub /'/, "\\\\\\&" # $ Alert // NOT OK
|
||||
s1.gsub /'/, '\\\\\&' # $ Alert // NOT OK
|
||||
s2.gsub! /'/, "\\\\\\&" # $ Alert // NOT OK
|
||||
s3.gsub! /'/, '\\\\\&' # $ Alert // NOT OK
|
||||
s1.gsub /'/, "\\\\\\&" # NOT OK
|
||||
s1.gsub /'/, '\\\\\&' # NOT OK
|
||||
s2.gsub! /'/, "\\\\\\&" # NOT OK
|
||||
s3.gsub! /'/, '\\\\\&' # NOT OK
|
||||
end
|
||||
|
||||
def bad5(s)
|
||||
s.gsub /['"]/, '\\\\\&' # $ Alert // NOT OK
|
||||
s.gsub! /['"]/, '\\\\\&' # $ Alert // NOT OK
|
||||
s.gsub /['"]/, '\\\\\&' # NOT OK
|
||||
s.gsub! /['"]/, '\\\\\&' # NOT OK
|
||||
end
|
||||
|
||||
def bad6(s)
|
||||
s.gsub /(['"])/, '\\\\\\1' # $ Alert // NOT OK
|
||||
s.gsub! /(['"])/, '\\\\\\1' # $ Alert // NOT OK
|
||||
s.gsub /(['"])/, '\\\\\\1' # NOT OK
|
||||
s.gsub! /(['"])/, '\\\\\\1' # NOT OK
|
||||
end
|
||||
|
||||
def bad7(s)
|
||||
s.gsub /('|")/, '\\\\\1' # $ Alert // NOT OK
|
||||
s.gsub! /('|")/, '\\\\\1' # $ Alert // NOT OK
|
||||
s.gsub /('|")/, '\\\\\1' # NOT OK
|
||||
s.gsub! /('|")/, '\\\\\1' # NOT OK
|
||||
end
|
||||
|
||||
def bad8(s)
|
||||
s.sub '|', '' # $ Alert // NOT OK
|
||||
s.sub! '|', '' # $ Alert // NOT OK
|
||||
s.sub '|', '' # NOT OK
|
||||
s.sub! '|', '' # NOT OK
|
||||
end
|
||||
|
||||
def bad9(s1, s2, s3, s4)
|
||||
s1.gsub /"/, "\\\"" # $ Alert // NOT OK
|
||||
s1.gsub /"/, '\\"' # $ Alert // NOT OK
|
||||
s1.gsub '"', '\\"' # $ Alert // NOT OK
|
||||
s2.gsub! /"/, "\\\"" # $ Alert // NOT OK
|
||||
s3.gsub! /"/, '\\"' # $ Alert // NOT OK
|
||||
s4.gsub! '"', '\\"' # $ Alert // NOT OK
|
||||
s1.gsub /"/, "\\\"" # NOT OK
|
||||
s1.gsub /"/, '\\"' # NOT OK
|
||||
s1.gsub '"', '\\"' # NOT OK
|
||||
s2.gsub! /"/, "\\\"" # NOT OK
|
||||
s3.gsub! /"/, '\\"' # NOT OK
|
||||
s4.gsub! '"', '\\"' # NOT OK
|
||||
end
|
||||
|
||||
def bad10(s)
|
||||
s.sub "/", "%2F" # $ Alert // NOT OK
|
||||
s.sub! "/", "%2F" # $ Alert // NOT OK
|
||||
s.sub "/", "%2F" # NOT OK
|
||||
s.sub! "/", "%2F" # NOT OK
|
||||
end
|
||||
|
||||
def bad11(s)
|
||||
s.sub "%25", "%" # $ Alert // NOT OK
|
||||
s.sub! "%25", "%" # $ Alert // NOT OK
|
||||
s.sub "%25", "%" # NOT OK
|
||||
s.sub! "%25", "%" # NOT OK
|
||||
end
|
||||
|
||||
def bad12(s)
|
||||
s.sub %q['], %q[] # $ Alert // NOT OK
|
||||
s.sub! %q['], %q[] # $ Alert // NOT OK
|
||||
s.sub %q['], %q[] # NOT OK
|
||||
s.sub! %q['], %q[] # NOT OK
|
||||
end
|
||||
|
||||
def bad13(s)
|
||||
s.sub "'" + "", "" # $ Alert // NOT OK
|
||||
s.sub! "'" + "", "" # $ Alert // NOT OK
|
||||
s.sub "'" + "", "" # NOT OK
|
||||
s.sub! "'" + "", "" # NOT OK
|
||||
end
|
||||
|
||||
def bad14(s)
|
||||
s.sub "'", "" + "" # $ Alert // NOT OK
|
||||
s.sub! "'", "" + "" # $ Alert // NOT OK
|
||||
s.sub "'", "" + "" # NOT OK
|
||||
s.sub! "'", "" + "" # NOT OK
|
||||
end
|
||||
|
||||
def bad15(s)
|
||||
s.sub "'" + "", "" + "" # $ Alert // NOT OK
|
||||
s.sub! "'" + "", "" + "" # $ Alert // NOT OK
|
||||
s.sub "'" + "", "" + "" # NOT OK
|
||||
s.sub! "'" + "", "" + "" # NOT OK
|
||||
end
|
||||
|
||||
def bad16(s)
|
||||
indirect = /'/
|
||||
s.sub(indirect, "") # $ Alert // NOT OK
|
||||
s.sub!(indirect, "") # $ Alert // NOT OK
|
||||
s.sub(indirect, "") # NOT OK
|
||||
s.sub!(indirect, "") # NOT OK
|
||||
end
|
||||
|
||||
def good1a(s)
|
||||
@@ -212,15 +212,15 @@ def good13a(s)
|
||||
s.sub('[', '').sub(']', '') # OK
|
||||
s.sub('(', '').sub(')', '') # OK
|
||||
s.sub('{', '').sub('}', '') # OK
|
||||
s.sub('<', '').sub('>', '') # $ Alert // NOT OK: too common as a bad HTML sanitizer
|
||||
s.sub('<', '').sub('>', '') # NOT OK: too common as a bad HTML sanitizer
|
||||
|
||||
s.sub('[', '\\[').sub(']', '\\]') # $ Alert // NOT OK
|
||||
s.sub('{', '\\{').sub('}', '\\}') # $ Alert // NOT OK
|
||||
s.sub('[', '\\[').sub(']', '\\]') # NOT OK
|
||||
s.sub('{', '\\{').sub('}', '\\}') # NOT OK
|
||||
|
||||
s = s.sub('[', '') # OK
|
||||
s = s.sub(']', '') # OK
|
||||
s.sub(/{/, '').sub(/}/, '') # OK
|
||||
s.sub(']', '').sub('[', '') # $ Alert // probably OK, but still flagged
|
||||
s.sub(']', '').sub('[', '') # probably OK, but still flagged
|
||||
end
|
||||
|
||||
def good13b(s1)
|
||||
@@ -245,8 +245,8 @@ def newlines_a(a, b, c)
|
||||
# motivation for whitelist
|
||||
`which emacs`.sub("\n", "") # OK
|
||||
|
||||
a.sub("\n", "").sub(b, c) # $ Alert // NOT OK
|
||||
a.sub(b, c).sub("\n", "") # $ Alert // NOT OK
|
||||
a.sub("\n", "").sub(b, c) # NOT OK
|
||||
a.sub(b, c).sub("\n", "") # NOT OK
|
||||
end
|
||||
|
||||
def newlines_b(a, b, c)
|
||||
@@ -255,18 +255,18 @@ def newlines_b(a, b, c)
|
||||
output.sub!("\n", "") # OK
|
||||
|
||||
d = a.dup
|
||||
d.sub!("\n", "") # $ Alert // NOT OK
|
||||
d.sub!("\n", "") # NOT OK
|
||||
d.sub!(b, c)
|
||||
|
||||
e = a.dup
|
||||
d.sub!(b, c)
|
||||
d.sub!("\n", "") # $ Alert // NOT OK
|
||||
d.sub!("\n", "") # NOT OK
|
||||
end
|
||||
|
||||
def bad_path_sanitizer(p1, p2)
|
||||
# attempt at path sanitization
|
||||
p1.sub! "/../", "" # $ Alert // NOT OK
|
||||
p2.sub "/../", "" # $ Alert // NOT OK
|
||||
p1.sub! "/../", "" # NOT OK
|
||||
p2.sub "/../", "" # NOT OK
|
||||
end
|
||||
|
||||
def each_line_sanitizer(p1)
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-117/LogInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-117/LogInjection.ql
|
||||
@@ -12,9 +12,9 @@ class UsersController < ApplicationController
|
||||
def read_from_params
|
||||
init_logger
|
||||
|
||||
unsanitized = params[:foo] # $ Source
|
||||
@logger.debug unsanitized # $ Alert // BAD: unsanitized user input
|
||||
@logger.error "input: " + unsanitized # $ Alert // BAD: unsanitized user input
|
||||
unsanitized = params[:foo]
|
||||
@logger.debug unsanitized # BAD: unsanitized user input
|
||||
@logger.error "input: " + unsanitized # BAD: unsanitized user input
|
||||
|
||||
sanitized = unsanitized.gsub("\n", "")
|
||||
@logger.fatal sanitized # GOOD: sanitized user input
|
||||
@@ -22,17 +22,17 @@ class UsersController < ApplicationController
|
||||
|
||||
unsanitized2 = unsanitized.sub("\n", "")
|
||||
@logger.info do
|
||||
unsanitized2 # $ Alert // BAD: partially sanitized user input
|
||||
unsanitized2 # BAD: partially sanitized user input
|
||||
end
|
||||
@logger << "input: " + unsanitized2 # $ Alert // BAD: partially sanitized user input
|
||||
@logger << "input: " + unsanitized2 # BAD: partially sanitized user input
|
||||
end
|
||||
|
||||
def read_from_cookies
|
||||
init_logger
|
||||
|
||||
unsanitized = cookies[:bar] # $ Source
|
||||
@logger.add(Logger::INFO) { unsanitized } # $ Alert // BAD: unsanitized user input
|
||||
@logger.log(Logger::WARN) { "input: " + unsanitized } # $ Alert // BAD: unsanitized user input
|
||||
unsanitized = cookies[:bar]
|
||||
@logger.add(Logger::INFO) { unsanitized } # BAD: unsanitized user input
|
||||
@logger.log(Logger::WARN) { "input: " + unsanitized } # BAD: unsanitized user input
|
||||
end
|
||||
|
||||
def html_sanitization
|
||||
@@ -46,7 +46,7 @@ class UsersController < ApplicationController
|
||||
def inspect_sanitization
|
||||
init_logger
|
||||
|
||||
@logger.debug params[:foo] # $ Alert // BAD: unsanitized user input
|
||||
@logger.debug params[:foo] # BAD: unsanitized user input
|
||||
@logger.debug params[:foo].inspect # GOOD: sanitized user input
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-1333/ReDoS.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-1333/ReDoS.ql
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# NOT GOOD; attack: "_" + "__".repeat(100)
|
||||
# Adapted from marked (https://github.com/markedjs/marked), which is licensed
|
||||
# under the MIT license; see file marked-LICENSE.
|
||||
bad1 = /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/ # $ Alert
|
||||
bad1 = /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/
|
||||
|
||||
# GOOD
|
||||
# Adapted from marked (https://github.com/markedjs/marked), which is licensed
|
||||
@@ -16,7 +16,7 @@ good2 = /(.*,)+.+/
|
||||
# NOT GOOD; attack: " '" + "\\\\".repeat(100)
|
||||
# Adapted from CodeMirror (https://github.com/codemirror/codemirror),
|
||||
# which is licensed under the MIT license; see file CodeMirror-LICENSE.
|
||||
bad2 = /^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/ # $ Alert
|
||||
bad2 = /^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/
|
||||
|
||||
# GOOD
|
||||
# Adapted from lulucms2 (https://github.com/yiifans/lulucms2).
|
||||
@@ -28,89 +28,89 @@ good2 = /\(\*(?:[\s\S]*?\(\*[\s\S]*?\*\))*[\s\S]*?\*\)/
|
||||
good3 = /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/
|
||||
|
||||
# NOT GOOD, variant of good3; attack: "a|\n:|\n" + "||\n".repeat(100)
|
||||
bad4 = /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)a/ # $ Alert
|
||||
bad4 = /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)a/
|
||||
|
||||
# NOT GOOD; attack: "/" + "\\/a".repeat(100)
|
||||
# Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog),
|
||||
# which is licensed under the Apache License 2.0; see file ANodeBlog-LICENSE.
|
||||
bad5 = /\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/ # $ Alert
|
||||
bad5 = /\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/
|
||||
|
||||
# NOT GOOD; attack: "##".repeat(100) + "\na"
|
||||
# Adapted from CodeMirror (https://github.com/codemirror/codemirror),
|
||||
# which is licensed under the MIT license; see file CodeMirror-LICENSE.
|
||||
bad6 = /^([\s\[\{\(]|#.*)*$/ # $ Alert
|
||||
bad6 = /^([\s\[\{\(]|#.*)*$/
|
||||
|
||||
# GOOD
|
||||
good4 = /(\r\n|\r|\n)+/
|
||||
|
||||
# BAD - PoC: `node -e "/((?:[^\"\']|\".*?\"|\'.*?\')*?)([(,)]|$)/.test(\"'''''''''''''''''''''''''''''''''''''''''''''\\\"\");"`. It's complicated though, because the regexp still matches something, it just matches the empty-string after the attack string.
|
||||
actuallyBad = /((?:[^"']|".*?"|'.*?')*?)([(,)]|$)/ # $ Alert
|
||||
actuallyBad = /((?:[^"']|".*?"|'.*?')*?)([(,)]|$)/
|
||||
|
||||
# NOT GOOD; attack: "a" + "[]".repeat(100) + ".b\n"
|
||||
# Adapted from Knockout (https://github.com/knockout/knockout), which is
|
||||
# licensed under the MIT license; see file knockout-LICENSE
|
||||
bad6 = /^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$/i # $ Alert
|
||||
bad6 = /^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$/i
|
||||
|
||||
# GOOD
|
||||
good6 = /(a|.)*/
|
||||
|
||||
# Testing the NFA - only some of the below are detected.
|
||||
bad7 = /^([a-z]+)+$/ # $ Alert
|
||||
bad8 = /^([a-z]*)*$/ # $ Alert
|
||||
bad9 = /^([a-zA-Z0-9])(([\\.-]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/ # $ Alert
|
||||
bad10 = /^(([a-z])+.)+[A-Z]([a-z])+$/ # $ Alert
|
||||
bad7 = /^([a-z]+)+$/
|
||||
bad8 = /^([a-z]*)*$/
|
||||
bad9 = /^([a-zA-Z0-9])(([\\.-]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/
|
||||
bad10 = /^(([a-z])+.)+[A-Z]([a-z])+$/
|
||||
|
||||
# NOT GOOD; attack: "[" + "][".repeat(100) + "]!"
|
||||
# Adapted from Prototype.js (https://github.com/prototypejs/prototype), which
|
||||
# is licensed under the MIT license; see file Prototype.js-LICENSE.
|
||||
bad11 = /(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/ # $ Alert
|
||||
bad11 = /(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/
|
||||
|
||||
# NOT GOOD; attack: "'" + "\\a".repeat(100) + '"'
|
||||
# Adapted from Prism (https://github.com/PrismJS/prism), which is licensed
|
||||
# under the MIT license; see file Prism-LICENSE.
|
||||
bad12 = /("|')(\\?.)*?\1/ # $ Alert
|
||||
bad12 = /("|')(\\?.)*?\1/
|
||||
|
||||
# NOT GOOD
|
||||
bad13 = /(b|a?b)*c/ # $ Alert
|
||||
bad13 = /(b|a?b)*c/
|
||||
|
||||
# NOT GOOD
|
||||
bad15 = /(a|aa?)*b/ # $ Alert
|
||||
bad15 = /(a|aa?)*b/
|
||||
|
||||
# GOOD
|
||||
good7 = /(.|\n)*!/
|
||||
|
||||
# NOT GOOD; attack: "\n".repeat(100) + "."
|
||||
bad16 = /(.|\n)*!/m # $ Alert
|
||||
bad16 = /(.|\n)*!/m
|
||||
|
||||
# GOOD
|
||||
good8 = /([\w.]+)*/
|
||||
|
||||
# NOT GOOD
|
||||
bad17 = Regexp.new '(a|aa?)*b' # $ Alert
|
||||
bad17 = Regexp.new '(a|aa?)*b'
|
||||
|
||||
# GOOD - not used as regexp
|
||||
good9 = '(a|aa?)*b'
|
||||
|
||||
# NOT GOOD
|
||||
bad18 = /(([\S\s]|[^a])*)"/ # $ Alert
|
||||
bad18 = /(([\S\s]|[^a])*)"/
|
||||
|
||||
# GOOD - there is no witness in the end that could cause the regexp to not match
|
||||
good10 = /([^"']+)*/
|
||||
|
||||
# NOT GOOD
|
||||
bad20 = /((.|[^a])*)"/ # $ Alert
|
||||
bad20 = /((.|[^a])*)"/
|
||||
|
||||
# GOOD
|
||||
good10 = /((a|[^a])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad21 = /((b|[^a])*)"/ # $ Alert
|
||||
bad21 = /((b|[^a])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad22 = /((G|[^a])*)"/ # $ Alert
|
||||
bad22 = /((G|[^a])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad23 = /(([0-9]|[^a])*)"/ # $ Alert
|
||||
bad23 = /(([0-9]|[^a])*)"/
|
||||
|
||||
# BAD - missing result
|
||||
bad24 = /(?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"))?/
|
||||
@@ -122,55 +122,55 @@ bad25 = /"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"/
|
||||
bad26 = /"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad27 = /(([a-z]|[d-h])*)"/ # $ Alert
|
||||
bad27 = /(([a-z]|[d-h])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad27 = /(([^a-z]|[^0-9])*)"/ # $ Alert
|
||||
bad27 = /(([^a-z]|[^0-9])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad28 = /((\d|[0-9])*)"/ # $ Alert
|
||||
bad28 = /((\d|[0-9])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad29 = /((\s|\s)*)"/ # $ Alert
|
||||
bad29 = /((\s|\s)*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad30 = /((\w|G)*)"/ # $ Alert
|
||||
bad30 = /((\w|G)*)"/
|
||||
|
||||
# GOOD
|
||||
good11 = /((\s|\d)*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad31 = /((\d|\w)*)"/ # $ Alert
|
||||
bad31 = /((\d|\w)*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad32 = /((\d|5)*)"/ # $ Alert
|
||||
bad32 = /((\d|5)*)"/
|
||||
|
||||
# BAD - \f is not handled correctly
|
||||
bad33 = /((\s|[\f])*)"/ # $ Alert
|
||||
bad33 = /((\s|[\f])*)"/
|
||||
|
||||
# BAD - \v is not handled correctly
|
||||
bad34 = /((\s|[\v]|\\v)*)"/ # $ Alert
|
||||
bad34 = /((\s|[\v]|\\v)*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad35 = /((\f|[\f])*)"/ # $ Alert
|
||||
bad35 = /((\f|[\f])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad36 = /((\W|\D)*)"/ # $ Alert
|
||||
bad36 = /((\W|\D)*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad37 = /((\S|\w)*)"/ # $ Alert
|
||||
bad37 = /((\S|\w)*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad38 = /((\S|[\w])*)"/ # $ Alert
|
||||
bad38 = /((\S|[\w])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad39 = /((1s|[\da-z])*)"/ # $ Alert
|
||||
bad39 = /((1s|[\da-z])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad40 = /((0|[\d])*)"/ # $ Alert
|
||||
bad40 = /((0|[\d])*)"/
|
||||
|
||||
# NOT GOOD
|
||||
bad41 = /(([\d]+)*)"/ # $ Alert
|
||||
bad41 = /(([\d]+)*)"/
|
||||
|
||||
# GOOD - there is no witness in the end that could cause the regexp to not match
|
||||
good12 = /(\d+(X\d+)?)+/
|
||||
@@ -182,49 +182,49 @@ good13 = /([0-9]+(X[0-9]*)?)*/
|
||||
good15 = /^([^>]+)*(>|$)/
|
||||
|
||||
# NOT GOOD
|
||||
bad43 = /^([^>a]+)*(>|$)/ # $ Alert
|
||||
bad43 = /^([^>a]+)*(>|$)/
|
||||
|
||||
# NOT GOOD
|
||||
bad44 = /(\n\s*)+$/ # $ Alert
|
||||
bad44 = /(\n\s*)+$/
|
||||
|
||||
# NOT GOOD
|
||||
bad45 = /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/ # $ Alert
|
||||
bad45 = /^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})/
|
||||
|
||||
# NOT GOOD
|
||||
bad46 = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}/ # $ Alert
|
||||
bad46 = /\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}/
|
||||
|
||||
# NOT GOOD
|
||||
bad47 = /(a+|b+|c+)*c/ # $ Alert
|
||||
bad47 = /(a+|b+|c+)*c/
|
||||
|
||||
# NOT GOOD
|
||||
bad48 = /(((a+a?)*)+b+)/ # $ Alert
|
||||
bad48 = /(((a+a?)*)+b+)/
|
||||
|
||||
# NOT GOOD
|
||||
bad49 = /(a+)+bbbb/ # $ Alert
|
||||
bad49 = /(a+)+bbbb/
|
||||
|
||||
# GOOD
|
||||
good16 = /(a+)+aaaaa*a+/
|
||||
|
||||
# NOT GOOD
|
||||
bad50 = /(a+)+aaaaa$/ # $ Alert
|
||||
bad50 = /(a+)+aaaaa$/
|
||||
|
||||
# GOOD
|
||||
good17 = /(\n+)+\n\n/
|
||||
|
||||
# NOT GOOD
|
||||
bad51 = /(\n+)+\n\n$/ # $ Alert
|
||||
bad51 = /(\n+)+\n\n$/
|
||||
|
||||
# NOT GOOD
|
||||
bad52 = /([^X]+)*$/ # $ Alert
|
||||
bad52 = /([^X]+)*$/
|
||||
|
||||
# NOT GOOD
|
||||
bad53 = /(([^X]b)+)*$/ # $ Alert
|
||||
bad53 = /(([^X]b)+)*$/
|
||||
|
||||
# GOOD
|
||||
good18 = /(([^X]b)+)*($|[^X]b)/
|
||||
|
||||
# NOT GOOD
|
||||
bad54 = /(([^X]b)+)*($|[^X]c)/ # $ Alert
|
||||
bad54 = /(([^X]b)+)*($|[^X]c)/
|
||||
|
||||
# GOOD
|
||||
good20 = /((ab)+)*ababab/
|
||||
@@ -236,13 +236,13 @@ good21 = /((ab)+)*abab(ab)*(ab)+/
|
||||
good22 = /((ab)+)*/
|
||||
|
||||
# NOT GOOD
|
||||
bad55 = /((ab)+)*$/ # $ Alert
|
||||
bad55 = /((ab)+)*$/
|
||||
|
||||
# GOOD
|
||||
good23 = /((ab)+)*[a1][b1][a2][b2][a3][b3]/
|
||||
|
||||
# NOT GOOD
|
||||
bad56 = /([\n\s]+)*(.)/ # $ Alert
|
||||
bad56 = /([\n\s]+)*(.)/
|
||||
|
||||
# GOOD - any witness passes through the accept state.
|
||||
good24 = /(A*A*X)*/
|
||||
@@ -251,13 +251,13 @@ good24 = /(A*A*X)*/
|
||||
good26 = /([^\\\]]+)*/
|
||||
|
||||
# NOT GOOD
|
||||
bad59 = /(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-/ # $ Alert
|
||||
bad59 = /(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-/
|
||||
|
||||
# NOT GOOD
|
||||
bad60 = /(.thisisagoddamnlongstringforstresstestingthequery|\sthisisagoddamnlongstringforstresstestingthequery)*-/ # $ Alert
|
||||
bad60 = /(.thisisagoddamnlongstringforstresstestingthequery|\sthisisagoddamnlongstringforstresstestingthequery)*-/
|
||||
|
||||
# NOT GOOD
|
||||
bad61 = /(thisisagoddamnlongstringforstresstestingthequery|this\w+query)*-/ # $ Alert
|
||||
bad61 = /(thisisagoddamnlongstringforstresstestingthequery|this\w+query)*-/
|
||||
|
||||
# GOOD
|
||||
good27 = /(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelatedstringcomparedtotheotherstring)*-/
|
||||
@@ -269,58 +269,58 @@ good27 = /(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelate
|
||||
#good29 = /foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo/
|
||||
|
||||
# NOT GOOD (but cannot currently construct a prefix)
|
||||
bad62 = /a{2,3}(b+)+X/ # $ Alert
|
||||
bad62 = /a{2,3}(b+)+X/
|
||||
|
||||
# NOT GOOD (and a good prefix test)
|
||||
bad63 = /^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/ # $ Alert
|
||||
bad63 = /^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/
|
||||
|
||||
# GOOD
|
||||
good30 = /(a+)*[\S\s][\S\s][\S\s]?/
|
||||
|
||||
# GOOD - but we fail to see that repeating the attack string ends in the "accept any" state (due to not parsing the range `[^]{2,3}`).
|
||||
good31 = /(a+)*[\S\s]{2,3}/ # $ Alert
|
||||
good31 = /(a+)*[\S\s]{2,3}/
|
||||
|
||||
# GOOD - but we spuriously conclude that a rejecting suffix exists (due to not parsing the range `[^]{2,}` when constructing the NFA).
|
||||
good32 = /(a+)*([\S\s]{2,}|X)$/ # $ Alert
|
||||
good32 = /(a+)*([\S\s]{2,}|X)$/
|
||||
|
||||
# GOOD
|
||||
good33 = /(a+)*([\S\s]*|X)$/
|
||||
|
||||
# NOT GOOD
|
||||
bad64 = /((a+)*$|[\S\s]+)/ # $ Alert
|
||||
bad64 = /((a+)*$|[\S\s]+)/
|
||||
|
||||
# GOOD - but still flagged. The only change compared to the above is the order of alternatives, which we don't model.
|
||||
good34 = /([\S\s]+|(a+)*$)/ # $ Alert
|
||||
good34 = /([\S\s]+|(a+)*$)/
|
||||
|
||||
# GOOD
|
||||
good35 = /((;|^)a+)+$/
|
||||
|
||||
# NOT GOOD (a good prefix test)
|
||||
bad65 = /(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f/ # $ Alert
|
||||
bad65 = /(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f/
|
||||
|
||||
# NOT GOOD
|
||||
bad66 = /^ab(c+)+$/ # $ Alert
|
||||
bad66 = /^ab(c+)+$/
|
||||
|
||||
# NOT GOOD
|
||||
bad67 = /(\d(\s+)*){20}/ # $ Alert
|
||||
bad67 = /(\d(\s+)*){20}/
|
||||
|
||||
# GOOD - but we spuriously conclude that a rejecting suffix exists.
|
||||
good36 = /(([^\/]|X)+)(\/[\S\s]*)*$/ # $ Alert
|
||||
good36 = /(([^\/]|X)+)(\/[\S\s]*)*$/
|
||||
|
||||
# GOOD - but we spuriously conclude that a rejecting suffix exists.
|
||||
good37 = /^((x([^Y]+)?)*(Y|$))/ # $ Alert
|
||||
good37 = /^((x([^Y]+)?)*(Y|$))/
|
||||
|
||||
# NOT GOOD
|
||||
bad68 = /(a*)+b/ # $ Alert
|
||||
bad68 = /(a*)+b/
|
||||
|
||||
# NOT GOOD
|
||||
bad69 = /foo([\w-]*)+bar/ # $ Alert
|
||||
bad69 = /foo([\w-]*)+bar/
|
||||
|
||||
# NOT GOOD
|
||||
bad70 = /((ab)*)+c/ # $ Alert
|
||||
bad70 = /((ab)*)+c/
|
||||
|
||||
# NOT GOOD
|
||||
bad71 = /(a?a?)*b/ # $ Alert
|
||||
bad71 = /(a?a?)*b/
|
||||
|
||||
# GOOD
|
||||
good38 = /(a?)*b/
|
||||
@@ -329,54 +329,54 @@ good38 = /(a?)*b/
|
||||
bad72 = /(c?a?)*b/
|
||||
|
||||
# NOT GOOD
|
||||
bad73 = /(?:a|a?)+b/ # $ Alert
|
||||
bad73 = /(?:a|a?)+b/
|
||||
|
||||
# NOT GOOD - but not detected.
|
||||
bad74 = /(a?b?)*$/
|
||||
|
||||
# NOT GOOD
|
||||
bad76 = /PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)/ # $ Alert
|
||||
bad76 = /PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)/
|
||||
|
||||
# NOT GOOD - but not detected
|
||||
bad77 = /^((a)+\w)+$/ # $ Alert
|
||||
bad77 = /^((a)+\w)+$/
|
||||
|
||||
# NOT GOOD
|
||||
bad78 = /^(b+.)+$/ # $ Alert
|
||||
bad78 = /^(b+.)+$/
|
||||
|
||||
# GOOD
|
||||
good39 = /a*b/
|
||||
|
||||
# All 4 bad combinations of nested * and +
|
||||
bad79 = /(a*)*b/ # $ Alert
|
||||
bad80 = /(a+)*b/ # $ Alert
|
||||
bad81 = /(a*)+b/ # $ Alert
|
||||
bad82 = /(a+)+b/ # $ Alert
|
||||
bad79 = /(a*)*b/
|
||||
bad80 = /(a+)*b/
|
||||
bad81 = /(a*)+b/
|
||||
bad82 = /(a+)+b/
|
||||
|
||||
# GOOD
|
||||
good40 = /(a|b)+/
|
||||
good41 = /(?:[\s;,"'<>(){}|\[\]@=+*]|:(?![\/\\]))+/
|
||||
|
||||
# NOT GOOD
|
||||
bad83 = /^((?:a{|-)|\w\{)+X$/ # $ Alert
|
||||
bad84 = /^((?:a{0|-)|\w\{\d)+X$/ # $ Alert
|
||||
bad85 = /^((?:a{0,|-)|\w\{\d,)+X$/ # $ Alert
|
||||
bad86 = /^((?:a{0,2|-)|\w\{\d,\d)+X$/ # $ Alert
|
||||
bad83 = /^((?:a{|-)|\w\{)+X$/
|
||||
bad84 = /^((?:a{0|-)|\w\{\d)+X$/
|
||||
bad85 = /^((?:a{0,|-)|\w\{\d,)+X$/
|
||||
bad86 = /^((?:a{0,2|-)|\w\{\d,\d)+X$/
|
||||
|
||||
# NOT GOOD
|
||||
bad87 = /^((?:a{0,2}|-)|\w\{\d,\d\})+X$/
|
||||
|
||||
# NOT GOOD
|
||||
bad88 = /^X(\u0061|a)*Y$/ # $ Alert
|
||||
bad88 = /^X(\u0061|a)*Y$/
|
||||
|
||||
# GOOD
|
||||
good43 = /^X(\u0061|b)+Y$/
|
||||
|
||||
# NOT GOOD
|
||||
bad88 = /X([[:digit:]]|\d)+Y/ # $ Alert
|
||||
bad88 = /X([[:digit:]]|\d)+Y/
|
||||
|
||||
# NOT GOOD
|
||||
bad89 = /\G(a|\w)*$/ # $ Alert
|
||||
bad90 = /\b(a|\w)*$/ # $ Alert
|
||||
bad89 = /\G(a|\w)*$/
|
||||
bad90 = /\b(a|\w)*$/
|
||||
|
||||
# NOT GOOD; attack: "0".repeat(30) + "!"
|
||||
# Adapated from addressable (https://github.com/sporkmonger/addressable)
|
||||
@@ -387,5 +387,5 @@ module Bad91
|
||||
var_char_class = ALPHA + DIGIT + '_'
|
||||
var_char = "(?:(?:[#{var_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)"
|
||||
var = "(?:#{var_char}(?:\\.?#{var_char})*)"
|
||||
bad91 = /^#{var}$/ # $ Alert
|
||||
bad91 = /^#{var}$/
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-1333/PolynomialReDoS.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-1333/PolynomialReDoS.ql
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
class FooController < ActionController::Base
|
||||
def some_request_handler
|
||||
# A source for the data-flow query (i.e. a remote flow source)
|
||||
name = params[:name] # $ Source
|
||||
name = params[:name]
|
||||
|
||||
# A vulnerable regex
|
||||
regex = /^\s+|\s+$/
|
||||
|
||||
# Various sinks that match the source against the regex
|
||||
name =~ regex # $ Alert // NOT GOOD
|
||||
name !~ regex # $ Alert // NOT GOOD
|
||||
name[regex] # $ Alert // NOT GOOD
|
||||
name.gsub regex, '' # $ Alert // NOT GOOD
|
||||
name.index regex # $ Alert // NOT GOOD
|
||||
name.match regex # $ Alert // NOT GOOD
|
||||
name.match? regex # $ Alert // NOT GOOD
|
||||
name.partition regex # $ Alert // NOT GOOD
|
||||
name.rindex regex # $ Alert // NOT GOOD
|
||||
name.rpartition regex # $ Alert // NOT GOOD
|
||||
name.scan regex # $ Alert // NOT GOOD
|
||||
name.split regex # $ Alert // NOT GOOD
|
||||
name.sub regex, '' # $ Alert // NOT GOOD
|
||||
regex.match name # $ Alert // NOT GOOD
|
||||
regex.match? name # $ Alert // NOT GOOD
|
||||
name =~ regex # NOT GOOD
|
||||
name !~ regex # NOT GOOD
|
||||
name[regex] # NOT GOOD
|
||||
name.gsub regex, '' # NOT GOOD
|
||||
name.index regex # NOT GOOD
|
||||
name.match regex # NOT GOOD
|
||||
name.match? regex # NOT GOOD
|
||||
name.partition regex # NOT GOOD
|
||||
name.rindex regex # NOT GOOD
|
||||
name.rpartition regex # NOT GOOD
|
||||
name.scan regex # NOT GOOD
|
||||
name.split regex # NOT GOOD
|
||||
name.sub regex, '' # NOT GOOD
|
||||
regex.match name # NOT GOOD
|
||||
regex.match? name # NOT GOOD
|
||||
|
||||
# Destructive variants
|
||||
a = params[:b] # $ Source
|
||||
a.gsub! regex, '' # $ Alert // NOT GOOD
|
||||
b = params[:a] # $ Source
|
||||
b.slice! regex # $ Alert // NOT GOOD
|
||||
c = params[:c] # $ Source
|
||||
c.sub! regex, '' # $ Alert // NOT GOOD
|
||||
a = params[:b]
|
||||
a.gsub! regex, '' # NOT GOOD
|
||||
b = params[:a]
|
||||
b.slice! regex # NOT GOOD
|
||||
c = params[:c]
|
||||
c.sub! regex, '' # NOT GOOD
|
||||
|
||||
# GOOD - guarded by a string length check
|
||||
if name.length < 1024
|
||||
@@ -39,19 +39,19 @@ class FooController < ActionController::Base
|
||||
# GOOD - regex does not suffer from polynomial backtracking (regression test)
|
||||
params[:foo] =~ /\A[bc].*\Z/
|
||||
|
||||
case name # $ Sink // NOT GOOD
|
||||
case name # NOT GOOD
|
||||
when regex
|
||||
puts "foo"
|
||||
end # $ Alert
|
||||
end
|
||||
|
||||
case name # $ Sink // NOT GOOD
|
||||
case name # NOT GOOD
|
||||
in /^\s+|\s+$/ then
|
||||
puts "foo"
|
||||
end # $ Alert
|
||||
end
|
||||
end
|
||||
|
||||
def some_other_request_handle
|
||||
name = params[:name] # $ Source // source
|
||||
name = params[:name] # source
|
||||
|
||||
indirect_use_of_reg /^\s+|\s+$/, name
|
||||
|
||||
@@ -59,22 +59,22 @@ class FooController < ActionController::Base
|
||||
end
|
||||
|
||||
def indirect_use_of_reg (reg, input)
|
||||
input.gsub reg, '' # $ Alert // NOT GOOD
|
||||
input.gsub reg, '' # NOT GOOD
|
||||
end
|
||||
|
||||
def as_string_indirect (reg_as_string, input)
|
||||
input.match? reg_as_string, '' # $ Alert // NOT GOOD
|
||||
input.match? reg_as_string, '' # NOT GOOD
|
||||
end
|
||||
|
||||
def re_compile_indirect
|
||||
name = params[:name] # $ Source // source
|
||||
name = params[:name] # source
|
||||
|
||||
reg = Regexp.new '^\s+|\s+$'
|
||||
re_compile_indirect_2 reg, name
|
||||
end
|
||||
|
||||
def re_compile_indirect_2 (reg, input)
|
||||
input.gsub reg, '' # $ Alert // NOT GOOD
|
||||
input.gsub reg, '' # NOT GOOD
|
||||
end
|
||||
|
||||
# See https://github.com/dependabot/dependabot-core/blob/37dc1767fde9b7184020763f4d0c1434f93d11d6/python/lib/dependabot/python/requirement_parser.rb#L6-L25
|
||||
@@ -100,8 +100,8 @@ class FooController < ActionController::Base
|
||||
MARKER_EXPR = /(#{MARKER_EXPR_ONE}|\(\s*|\s*\)|\s+and\s+|\s+or\s+)+/
|
||||
|
||||
def use_marker_expr
|
||||
name = params[:name] # $ Source // source
|
||||
name = params[:name] # source
|
||||
|
||||
name =~ MARKER_EXPR # $ Alert
|
||||
name =~ MARKER_EXPR
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
module Foo
|
||||
def bar(x) # $ Source
|
||||
def bar(x)
|
||||
# Run the /a+$/ regex on the input x.
|
||||
match = x.match(/a+$/) # $ Alert
|
||||
match = x.match(/a+$/)
|
||||
end
|
||||
|
||||
protected
|
||||
def baz(x) # $ Source
|
||||
match = x.match(/a+$/) # $ Alert
|
||||
def baz(x)
|
||||
match = x.match(/a+$/)
|
||||
|
||||
match2 = x.match(/(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)C.*Y$/) # $ Alert
|
||||
match2 = x.match(/(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)C.*Y$/)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-1333/RegExpInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-1333/RegExpInjection.ql
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
class FooController < ActionController::Base
|
||||
# BAD
|
||||
def route0
|
||||
name = params[:name] # $ Source
|
||||
regex = /#{name}/ # $ Alert
|
||||
name = params[:name]
|
||||
regex = /#{name}/
|
||||
end
|
||||
|
||||
# BAD
|
||||
def route1
|
||||
name = params[:name] # $ Source
|
||||
regex = /foo#{name}bar/ # $ Alert
|
||||
name = params[:name]
|
||||
regex = /foo#{name}bar/
|
||||
end
|
||||
|
||||
# BAD
|
||||
def route2
|
||||
name = params[:name] # $ Source
|
||||
regex = Regexp.new(name) # $ Alert
|
||||
name = params[:name]
|
||||
regex = Regexp.new(name)
|
||||
end
|
||||
|
||||
# BAD
|
||||
def route3
|
||||
name = params[:name] # $ Source
|
||||
regex = Regexp.new("@" + name) # $ Alert
|
||||
name = params[:name]
|
||||
regex = Regexp.new("@" + name)
|
||||
end
|
||||
|
||||
# GOOD - string is compared against a constant string
|
||||
@@ -51,7 +51,7 @@ class FooController < ActionController::Base
|
||||
|
||||
# BAD
|
||||
def route8
|
||||
name = params[:name] # $ Source
|
||||
regex = Regexp.compile("@" + name) # $ Alert
|
||||
name = params[:name]
|
||||
regex = Regexp.compile("@" + name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-134/TaintedFormatString.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-134/TaintedFormatString.ql
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
class UsersController < ActionController::Base
|
||||
|
||||
def show
|
||||
printf(params[:format], arg) # $ Alert // BAD
|
||||
Kernel.printf(params[:format], arg) # $ Alert // BAD
|
||||
printf(params[:format], arg) # BAD
|
||||
Kernel.printf(params[:format], arg) # BAD
|
||||
|
||||
printf(params[:format]) # GOOD
|
||||
Kernel.printf(params[:format]) # GOOD
|
||||
|
||||
printf(IO.new(1), params[:format], arg) # $ Alert // BAD
|
||||
Kernel.printf(IO.new(1), params[:format], arg) # $ Alert // BAD
|
||||
printf(IO.new(1), params[:format], arg) # BAD
|
||||
Kernel.printf(IO.new(1), params[:format], arg) # BAD
|
||||
|
||||
printf("%s", params[:format]) # GOOD
|
||||
Kernel.printf("%s", params[:format]) # GOOD
|
||||
fmt = "%s"
|
||||
printf(fmt, params[:format]) # GOOD
|
||||
|
||||
printf(IO.new(1), params[:format]) # $ Alert // GOOD [FALSE POSITIVE]
|
||||
Kernel.printf(IO.new(1), params[:format]) # $ Alert // GOOD [FALSE POSITIVE]
|
||||
printf(IO.new(1), params[:format]) # GOOD [FALSE POSITIVE]
|
||||
Kernel.printf(IO.new(1), params[:format]) # GOOD [FALSE POSITIVE]
|
||||
|
||||
str1 = Kernel.sprintf(params[:format], arg) # $ Alert // BAD
|
||||
str2 = sprintf(params[:format], arg) # $ Alert // BAD
|
||||
str1 = Kernel.sprintf(params[:format], arg) # BAD
|
||||
str2 = sprintf(params[:format], arg) # BAD
|
||||
|
||||
str1 = Kernel.sprintf(params[:format]) # GOOD
|
||||
str2 = sprintf(params[:format]) # GOOD
|
||||
|
||||
stdout = IO.new 1
|
||||
stdout.printf(params[:format], arg) # $ Alert // BAD
|
||||
stdout.printf(params[:format], arg) # BAD
|
||||
|
||||
stdout.printf(params[:format]) # GOOD
|
||||
|
||||
# Taint via string concatenation
|
||||
printf("A log message: " + params[:format], arg) # $ Alert // BAD
|
||||
printf("A log message: " + params[:format], arg) # BAD
|
||||
|
||||
# Taint via string interpolation
|
||||
printf("A log message: #{params[:format]}", arg) # $ Alert // BAD
|
||||
printf("A log message: #{params[:format]}", arg) # BAD
|
||||
|
||||
# Using String#
|
||||
"A log message #{params[:format]} %{foo}" % {foo: "foo"} # $ Alert // BAD
|
||||
"A log message #{params[:format]} %{foo}" % {foo: "foo"} # BAD
|
||||
|
||||
# String# with an array
|
||||
"A log message #{params[:format]} %08x" % ["foo"] # $ Alert // BAD
|
||||
"A log message #{params[:format]} %08x" % ["foo"] # BAD
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-209/StackTraceExposure.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-209/StackTraceExposure.ql
|
||||
@@ -3,19 +3,19 @@ class FooController < ApplicationController
|
||||
def show
|
||||
something_that_might_fail()
|
||||
rescue => e
|
||||
render body: e.backtrace, content_type: "text/plain" # $ Alert
|
||||
render body: e.backtrace, content_type: "text/plain"
|
||||
end
|
||||
|
||||
|
||||
def show2
|
||||
bt = caller() # $ Source
|
||||
render body: bt, content_type: "text/plain" # $ Alert
|
||||
bt = caller()
|
||||
render body: bt, content_type: "text/plain"
|
||||
end
|
||||
|
||||
def show3
|
||||
not_a_method()
|
||||
rescue NoMethodError => e
|
||||
render body: e.backtrace, content_type: "text/plain" # $ Alert
|
||||
render body: e.backtrace, content_type: "text/plain"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -3,31 +3,31 @@ require "excon"
|
||||
def method1
|
||||
# BAD
|
||||
Excon.defaults[:ssl_verify_peer] = false
|
||||
Excon.get("http://example.com/") # $ Alert
|
||||
Excon.get("http://example.com/")
|
||||
end
|
||||
|
||||
def method2
|
||||
# BAD
|
||||
Excon.ssl_verify_peer = false
|
||||
Excon.get("http://example.com/") # $ Alert
|
||||
Excon.get("http://example.com/")
|
||||
end
|
||||
|
||||
def method3(secure)
|
||||
# BAD
|
||||
Excon.defaults[:ssl_verify_peer] = (secure ? true : false)
|
||||
Excon.get("http://example.com/") # $ Alert
|
||||
Excon.get("http://example.com/")
|
||||
end
|
||||
|
||||
def method4
|
||||
# BAD
|
||||
conn = Excon::Connection.new("http://example.com/", ssl_verify_peer: false)
|
||||
conn.get # $ Alert
|
||||
conn.get
|
||||
end
|
||||
|
||||
def method5
|
||||
# BAD
|
||||
Excon.ssl_verify_peer = true
|
||||
Excon.new("http://example.com/", ssl_verify_peer: false).get # $ Alert
|
||||
Excon.new("http://example.com/", ssl_verify_peer: false).get
|
||||
end
|
||||
|
||||
def method6
|
||||
@@ -65,4 +65,4 @@ def method10
|
||||
# GOOD
|
||||
connection = Excon.new("foo")
|
||||
connection.get("bar")
|
||||
end
|
||||
end
|
||||
@@ -2,11 +2,11 @@ require "faraday"
|
||||
|
||||
# BAD
|
||||
connection = Faraday.new("http://example.com", ssl: { verify: false })
|
||||
response = connection.get("/") # $ Alert
|
||||
response = connection.get("/")
|
||||
|
||||
# BAD
|
||||
connection = Faraday.new("http://example.com", ssl: { verify_mode: OpenSSL::SSL::VERIFY_NONE })
|
||||
response = connection.get("/") # $ Alert
|
||||
response = connection.get("/")
|
||||
|
||||
# GOOD
|
||||
connection = Faraday.new("http://example.com")
|
||||
@@ -32,7 +32,7 @@ response = connection.get("/")
|
||||
def verify_as_arg(host, path, arg)
|
||||
# BAD, due to the call below
|
||||
connection = Faraday.new(host, ssl: { verify: arg })
|
||||
response = connection.get(path) # $ Alert
|
||||
response = connection.get(path)
|
||||
end
|
||||
|
||||
verify_as_arg("http://example.com", "/", false)
|
||||
@@ -41,7 +41,7 @@ verify_as_arg("http://example.com", "/", false)
|
||||
def verify_mode_as_arg(host, path, arg)
|
||||
# BAD, due to the call below
|
||||
connection = Faraday.new(host, ssl: { verify_mode: arg })
|
||||
response = connection.get(path) # $ Alert
|
||||
response = connection.get(path)
|
||||
end
|
||||
|
||||
verify_mode_as_arg("http://example.com", "/", OpenSSL::SSL::VERIFY_NONE)
|
||||
|
||||
@@ -3,7 +3,7 @@ require "httpclient"
|
||||
# BAD
|
||||
client = HTTPClient.new
|
||||
client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
client.get("https://example.com") # $ Alert
|
||||
client.get("https://example.com")
|
||||
|
||||
# GOOD
|
||||
client = HTTPClient.new
|
||||
@@ -15,4 +15,4 @@ client = HTTPClient.new
|
||||
client.get("https://example.com")
|
||||
|
||||
# GOOD
|
||||
HTTPClient.get("https://example.com/")
|
||||
HTTPClient.get("https://example.com/")
|
||||
@@ -1,19 +1,19 @@
|
||||
require "httparty"
|
||||
|
||||
# BAD
|
||||
HTTParty.get("http://example.com/", verify: false) # $ Alert
|
||||
HTTParty.get("http://example.com/", verify: false)
|
||||
|
||||
# BAD
|
||||
HTTParty.get("http://example.com/", verify_peer: false) # $ Alert
|
||||
HTTParty.get("http://example.com/", verify_peer: false)
|
||||
|
||||
# BAD
|
||||
HTTParty.get("http://example.com/", { verify_peer: false }) # $ Alert
|
||||
HTTParty.get("http://example.com/", { verify_peer: false })
|
||||
|
||||
# BAD
|
||||
HTTParty.post("http://example.com/", body: "some_data", verify: false) # $ Alert
|
||||
HTTParty.post("http://example.com/", body: "some_data", verify: false)
|
||||
|
||||
# BAD
|
||||
HTTParty.post("http://example.com/", { body: "some_data", verify: false }) # $ Alert
|
||||
HTTParty.post("http://example.com/", { body: "some_data", verify: false })
|
||||
|
||||
# GOOD
|
||||
HTTParty.get("http://example.com/")
|
||||
@@ -34,4 +34,4 @@ HTTParty.post("http://example.com/", body: "some_data", verify: true)
|
||||
HTTParty.post("http://example.com/", { body: "some_data" })
|
||||
|
||||
# GOOD
|
||||
HTTParty.post("http://example.com/", { body: "some_data", verify: true })
|
||||
HTTParty.post("http://example.com/", { body: "some_data", verify: true })
|
||||
@@ -6,5 +6,5 @@ http = Net::HTTP.new uri.host, uri.port
|
||||
http.use_ssl = true
|
||||
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
request = Net::HTTP::Get.new uri.request_uri
|
||||
response = http.request request # $ Alert
|
||||
response = http.request request
|
||||
puts response.body
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
require "open-uri"
|
||||
|
||||
# BAD
|
||||
Kernel.open("https://example.com", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) # $ Alert
|
||||
Kernel.open("https://example.com", ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
||||
|
||||
# BAD
|
||||
Kernel.open("https://example.com", { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }) # $ Alert
|
||||
Kernel.open("https://example.com", { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE })
|
||||
|
||||
# BAD
|
||||
options = { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }
|
||||
Kernel.open("https://example.com", options) # $ Alert
|
||||
Kernel.open("https://example.com", options)
|
||||
|
||||
# BAD
|
||||
URI.parse("https://example.com").open(ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE) # $ Alert
|
||||
URI.parse("https://example.com").open(ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
||||
|
||||
# BAD
|
||||
URI.parse("https://example.com").open({ ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }) # $ Alert
|
||||
URI.parse("https://example.com").open({ ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE })
|
||||
|
||||
# BAD
|
||||
options = { ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE }
|
||||
URI.parse("https://example.com").open(options) # $ Alert
|
||||
URI.parse("https://example.com").open(options)
|
||||
|
||||
# GOOD
|
||||
Kernel.open("https://example.com")
|
||||
@@ -44,4 +44,4 @@ URI.parse("https://example.com").open({ ssl_verify_mode: OpenSSL::SSL::VERIFY_PE
|
||||
|
||||
# GOOD
|
||||
options = { ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER }
|
||||
URI.parse("https://example.com").open(options)
|
||||
URI.parse("https://example.com").open(options)
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-295/RequestWithoutValidation.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-295/RequestWithoutValidation.ql
|
||||
@@ -2,21 +2,21 @@ require "rest-client"
|
||||
|
||||
# BAD
|
||||
resource = RestClient::Resource.new("https://example.com", verify_ssl: OpenSSL::SSL::VERIFY_NONE)
|
||||
response = resource.get # $ Alert
|
||||
response = resource.get
|
||||
|
||||
# BAD
|
||||
resource = RestClient::Resource.new("https://example.com", { verify_ssl: OpenSSL::SSL::VERIFY_NONE })
|
||||
response = resource.get # $ Alert
|
||||
response = resource.get
|
||||
|
||||
# BAD
|
||||
options = { verify_ssl: OpenSSL::SSL::VERIFY_NONE }
|
||||
resource = RestClient::Resource.new("https://example.com", options)
|
||||
response = resource.get # $ Alert
|
||||
response = resource.get
|
||||
|
||||
# BAD
|
||||
value = OpenSSL::SSL::VERIFY_NONE
|
||||
resource = RestClient::Resource.new("https://example.com", verify_ssl: value)
|
||||
response = resource.get # $ Alert
|
||||
response = resource.get
|
||||
|
||||
# GOOD
|
||||
RestClient.get("https://example.com")
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
require "typhoeus"
|
||||
|
||||
# BAD
|
||||
Typhoeus.get("https://www.example.com", ssl_verifypeer: false) # $ Alert
|
||||
Typhoeus.get("https://www.example.com", ssl_verifypeer: false)
|
||||
|
||||
# BAD
|
||||
post_options = { body: "some data", ssl_verifypeer: false }
|
||||
Typhoeus.post("https://www.example.com", post_options) # $ Alert
|
||||
Typhoeus.post("https://www.example.com", post_options)
|
||||
|
||||
# GOOD
|
||||
Typhoeus.get("https://www.example.com")
|
||||
Typhoeus.get("https://www.example.com")
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-312/CleartextLogging.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-312/CleartextLogging.ql
|
||||
@@ -1,2 +1 @@
|
||||
query: queries/security/cwe-312/CleartextStorage.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
queries/security/cwe-312/CleartextStorage.ql
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user