mirror of
https://github.com/github/codeql.git
synced 2026-06-12 08:21:09 +02:00
Compare commits
1 Commits
copilot/ql
...
mario-camp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
838d06c53f |
@@ -2,7 +2,7 @@
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
|
||||
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
|
||||
|
||||
## 0.4.36
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, include regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a sha1 or sha256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
|
||||
* The GitHub Actions analysis now recognizes more Bash regex checks that restrict a value to alphanumeric characters, including regexes like `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$` which check for a SHA-1 or SHA-256 hash. This may reduce false positive results where command output is validated with grouped or optional alphanumeric patterns before being used.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check.
|
||||
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check.
|
||||
|
||||
## 0.6.28
|
||||
|
||||
|
||||
@@ -15,4 +15,4 @@
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on in minor point, added one more listed resource and added one more recommendation for things to check.
|
||||
* Adjusted (minor) help file descriptions for queries: `actions/untrusted-checkout/critical`, `actions/untrusted-checkout/high`, `actions/untrusted-checkout/medium`. Clarified wording on a minor point, added one more listed resource and added one more recommendation for things to check.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added `UseMemoDirective` and `UseNoMemoDirective` classes to model the React compiler directives `"use memo"` and `"use no memo"`.
|
||||
@@ -435,32 +435,6 @@ module Directive {
|
||||
UseClientDirective() { this.getDirectiveText() = "use client" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `use memo` directive.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* "use memo";
|
||||
* ```
|
||||
*/
|
||||
class UseMemoDirective extends KnownDirective {
|
||||
UseMemoDirective() { this.getDirectiveText() = "use memo" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `use no memo` directive.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* "use no memo";
|
||||
* ```
|
||||
*/
|
||||
class UseNoMemoDirective extends KnownDirective {
|
||||
UseNoMemoDirective() { this.getDirectiveText() = "use no memo" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `use cache` directive.
|
||||
*
|
||||
|
||||
@@ -3,18 +3,14 @@
|
||||
| tst.js:3:1:3:9 | 'bundle'; | bundle |
|
||||
| tst.js:4:1:4:13 | 'use server'; | use server |
|
||||
| tst.js:5:1:5:13 | 'use client'; | use client |
|
||||
| tst.js:6:1:6:11 | 'use memo'; | use memo |
|
||||
| tst.js:7:1:7:14 | 'use no memo'; | use no memo |
|
||||
| tst.js:8:1:8:12 | 'use cache'; | use cache |
|
||||
| tst.js:9:1:9:20 | 'use cache: remote'; | use cache: remote |
|
||||
| tst.js:10:1:10:21 | 'use ca ... ivate'; | use cache: private |
|
||||
| tst.js:19:3:19:12 | 'use asm'; | use asm |
|
||||
| tst.js:20:3:20:11 | 'bundle'; | bundle |
|
||||
| tst.js:21:3:21:15 | 'use server'; | use server |
|
||||
| tst.js:22:3:22:15 | 'use client'; | use client |
|
||||
| tst.js:23:3:23:13 | 'use memo'; | use memo |
|
||||
| tst.js:24:3:24:16 | 'use no memo'; | use no memo |
|
||||
| tst.js:25:3:25:14 | 'use cache'; | use cache |
|
||||
| tst.js:26:3:26:22 | 'use cache: remote'; | use cache: remote |
|
||||
| tst.js:27:3:27:23 | 'use ca ... ivate'; | use cache: private |
|
||||
| tst.js:34:5:34:17 | 'use strict'; | use strict |
|
||||
| tst.js:6:1:6:12 | 'use cache'; | use cache |
|
||||
| tst.js:7:1:7:20 | 'use cache: remote'; | use cache: remote |
|
||||
| tst.js:8:1:8:21 | 'use ca ... ivate'; | use cache: private |
|
||||
| tst.js:17:3:17:12 | 'use asm'; | use asm |
|
||||
| tst.js:18:3:18:11 | 'bundle'; | bundle |
|
||||
| tst.js:19:3:19:15 | 'use server'; | use server |
|
||||
| tst.js:20:3:20:15 | 'use client'; | use client |
|
||||
| tst.js:21:3:21:14 | 'use cache'; | use cache |
|
||||
| tst.js:22:3:22:22 | 'use cache: remote'; | use cache: remote |
|
||||
| tst.js:23:3:23:23 | 'use ca ... ivate'; | use cache: private |
|
||||
| tst.js:30:5:30:17 | 'use strict'; | use strict |
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
'bundle';// and this
|
||||
'use server';
|
||||
'use client';
|
||||
'use memo';
|
||||
'use no memo';
|
||||
'use cache';
|
||||
'use cache: remote';
|
||||
'use cache: private';
|
||||
@@ -20,8 +18,6 @@ function f() {
|
||||
'bundle';
|
||||
'use server';
|
||||
'use client';
|
||||
'use memo';
|
||||
'use no memo';
|
||||
'use cache';
|
||||
'use cache: remote';
|
||||
'use cache: private';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and less fewer positive results after these changes.
|
||||
* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and fewer false positive results after these changes.
|
||||
|
||||
## 7.1.1
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and less fewer positive results after these changes.
|
||||
* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and fewer false positive results after these changes.
|
||||
|
||||
@@ -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)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user