diff --git a/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected new file mode 100644 index 0000000..9110e24 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected @@ -0,0 +1,30 @@ +| hosttest.rb:1:18:1:41 | (www\|beta).example.com\\/ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | hosttest.rb:1:17:1:42 | /(www\|beta).example.com\\// | here | +| hosttest.rb:2:33:2:55 | (www\|beta).example.com/ | This regular expression has an unescaped '.' before 'example.com/', so it might match more hosts than expected. | hosttest.rb:2:32:2:56 | "(www\|beta).example.com/" | here | +| hosttest.rb:3:29:3:51 | (www\|beta).example.com/ | This regular expression has an unescaped '.' before 'example.com/', so it might match more hosts than expected. | hosttest.rb:3:28:3:52 | "(www\|beta).example.com/" | here | +| tst-IncompleteHostnameRegExp.rb:3:3:3:28 | ^http:\\/\\/test.example.com | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:3:2:3:29 | /^http:\\/\\/test.example.com/ | here | +| tst-IncompleteHostnameRegExp.rb:5:3:5:28 | ^http:\\/\\/test.example.net | This regular expression has an unescaped '.' before 'example.net', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:5:2:5:29 | /^http:\\/\\/test.example.net/ | here | +| tst-IncompleteHostnameRegExp.rb:6:3:6:42 | ^http:\\/\\/test.(example-a\|example-b).com | This regular expression has an unescaped '.' before '(example-a\|example-b).com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:6:2:6:43 | /^http:\\/\\/test.(example-a\|exa.../ | here | +| tst-IncompleteHostnameRegExp.rb:7:3:7:30 | ^http:\\/\\/(.+).example.com\\/ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:7:2:7:31 | /^http:\\/\\/(.+).example.com\\// | here | +| tst-IncompleteHostnameRegExp.rb:7:3:7:30 | ^http:\\/\\/(.+).example.com\\/ | This regular expression has an unrestricted wildcard '.+' which may cause 'example.com' to be matched anywhere in the URL, outside the hostname. | tst-IncompleteHostnameRegExp.rb:7:2:7:31 | /^http:\\/\\/(.+).example.com\\// | here | +| tst-IncompleteHostnameRegExp.rb:9:3:9:39 | ^http:\\/\\/(?:.+)\\.test\\.example.com\\/ | This regular expression has an unrestricted wildcard '.+' which may cause 'example.com' to be matched anywhere in the URL, outside the hostname. | tst-IncompleteHostnameRegExp.rb:9:2:9:40 | /^http:\\/\\/(?:.+)\\.test\\.examp.../ | here | +| tst-IncompleteHostnameRegExp.rb:10:3:10:36 | ^http:\\/\\/test.example.com\\/(?:.*) | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:10:2:10:37 | /^http:\\/\\/test.example.com\\/(.../ | here | +| tst-IncompleteHostnameRegExp.rb:11:14:11:37 | ^http://test.example.com | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:11:13:11:38 | "^http://test.example.com" | here | +| tst-IncompleteHostnameRegExp.rb:12:15:12:38 | ^http://test.example.com | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:12:14:12:39 | "^http://test.example.com" | here | +| tst-IncompleteHostnameRegExp.rb:15:23:15:46 | ^http://test.example.com | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:15:13:15:50 | call to id | here | +| tst-IncompleteHostnameRegExp.rb:17:14:17:30 | test.example.com$ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:17:13:17:31 | `test.example.com$` | here | +| tst-IncompleteHostnameRegExp.rb:19:14:19:30 | ^test.example.com | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:20:13:20:26 | "#{...}$" | here | +| tst-IncompleteHostnameRegExp.rb:20:14:20:31 | ^test.example.com$ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:20:13:20:26 | "#{...}$" | here | +| tst-IncompleteHostnameRegExp.rb:22:24:22:40 | test.example.com$ | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:23:13:23:29 | ...[...] | here | +| tst-IncompleteHostnameRegExp.rb:28:24:28:40 | test.example.com$ | This string, which is used as a regular expression $@, has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:63:20:63:36 | ...[...] | here | +| tst-IncompleteHostnameRegExp.rb:37:3:37:53 | ^(https?:)?\\/\\/((service\|www).)?example.com(?=$\|\\/) | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:37:2:37:54 | /^(https?:)?\\/\\/((service\|www).../ | here | +| tst-IncompleteHostnameRegExp.rb:38:3:38:43 | ^(http\|https):\\/\\/www.example.com\\/p\\/f\\/ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:38:2:38:44 | /^(http\|https):\\/\\/www.example.../ | here | +| tst-IncompleteHostnameRegExp.rb:39:5:39:30 | http:\\/\\/sub.example.com\\/ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:39:2:39:33 | /^(http:\\/\\/sub.example.com\\/)/ | here | +| tst-IncompleteHostnameRegExp.rb:40:3:40:29 | ^https?:\\/\\/api.example.com | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:40:2:40:30 | /^https?:\\/\\/api.example.com/ | here | +| tst-IncompleteHostnameRegExp.rb:41:42:41:68 | ^https?://.+\\.example\\.com/ | This string, which is used as a regular expression $@, has an unrestricted wildcard '.+' which may cause 'example\\.com/' to be matched anywhere in the URL, outside the hostname. | tst-IncompleteHostnameRegExp.rb:41:13:41:71 | ... + ... | here | +| tst-IncompleteHostnameRegExp.rb:43:3:43:32 | ^https:\\/\\/[a-z]*.example.com$ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:43:2:43:33 | /^https:\\/\\/[a-z]*.example.com$/ | here | +| tst-IncompleteHostnameRegExp.rb:44:40:44:53 | .+.example.net | This regular expression has an unescaped '.' before 'example.net', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:44:17:44:109 | "^protos?://(localhost\|.+.exam..." | here | +| tst-IncompleteHostnameRegExp.rb:44:55:44:70 | .+.example-a.com | This regular expression has an unescaped '.' before 'example-a.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:44:17:44:109 | "^protos?://(localhost\|.+.exam..." | here | +| tst-IncompleteHostnameRegExp.rb:44:72:44:87 | .+.example-b.com | This regular expression has an unescaped '.' before 'example-b.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:44:17:44:109 | "^protos?://(localhost\|.+.exam..." | here | +| tst-IncompleteHostnameRegExp.rb:48:42:48:67 | ^https?://.+.example\\.com/ | This string, which is used as a regular expression $@, has an unescaped '.' before 'example\\.com/', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:48:13:48:69 | ... + ... | here | +| tst-IncompleteHostnameRegExp.rb:48:42:48:67 | ^https?://.+.example\\.com/ | This string, which is used as a regular expression $@, has an unrestricted wildcard '.+' which may cause 'example\\.com/' to be matched anywhere in the URL, outside the hostname. | tst-IncompleteHostnameRegExp.rb:48:13:48:69 | ... + ... | here | +| tst-IncompleteHostnameRegExp.rb:59:5:59:20 | foo.example\\.com | This regular expression has an unescaped '.' before 'example\\.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.rb:59:2:59:32 | /^(foo.example\\.com\|whatever)$/ | here | diff --git a/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref new file mode 100644 index 0000000..7fd45d1 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.qlref @@ -0,0 +1 @@ +queries/security/cwe-020/IncompleteHostnameRegExp.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/hosttest.rb b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/hosttest.rb new file mode 100644 index 0000000..5a5c966 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/hosttest.rb @@ -0,0 +1,22 @@ +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 + target = params[:target] + if UNSAFE_REGEX1.match(target) + redirect_to target + end +end + +def safe + target = params[:target] + if SAFE_REGEX.match(target) + redirect_to target + end +end + +# FP reported in https://github.com/github/codeql/issues/3712 +# This does not define a regex (but could be used by other code to do so) +escaped = Regexp::escape("https://www.humblebundle.com/home/library") diff --git a/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb new file mode 100644 index 0000000..842cd1f --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.rb @@ -0,0 +1,155 @@ +def foo +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + /^http:\/\/example.com/; # OK +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^http:\/\/test.example.com/; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + /^http:\/\/test\.example.com/; # OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^http:\/\/test.example.net/; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^http:\/\/test.(example-a|example-b).com/; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^http:\/\/(.+).example.com\//; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + /^http:\/\/(\.+)\.example.com/; # OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^http:\/\/(?:.+)\.test\.example.com\//; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + /^http:\/\/test.example.com\/(?:.*)/; # OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new("^http://test.example.com"); # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + if (s.match("^http://test.example.com")); end # NOT OK +# {/fact} + + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new(id(id(id("^http://test.example.com")))); # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new(`test.example.com$`); # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + hostname = '^test.example.com'; # NOT OK +# {/fact} + + Regexp.new("#{hostname}$"); + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + domain = { hostname: 'test.example.com$' }; # NOT OK +# {/fact} + + Regexp.new(domain[:hostname]); + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + convert1({ hostname: 'test.example.com$' }); # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + domains = [ { hostname: 'test.example.com$' } ]; # NOT OK - but not flagged due to limitations of TypeTracking. +# {/fact} + + + domains.map{ |d| convert2(d) }; + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^(.+\.(?:example-a|example-b)\.com)\//; # NOT OK + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^(https?:)?\/\/((service|www).)?example.com(?=$|\/)/; # NOT OK + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^(http|https):\/\/www.example.com\/p\/f\//; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^(http:\/\/sub.example.com\/)/i; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^https?:\/\/api.example.com/; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new('^http://localhost:8000|' + "^https?://.+\\.example\\.com/"); # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new("^http[s]?:\/\/?sub1\\.sub2\\.example\\.com\/f\/(.+)"); # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + /^https:\/\/[a-z]*.example.com$/; # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.compile('^protos?://(localhost|.+.example.net|.+.example-a.com|.+.example-b.com|.+.example.internal)'); # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + /^(example.dev|example.com)/; # OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new('^http://localhost:8000|' + "^https?://.+.example\\.com/"); # NOT OK +# {/fact} + + primary = 'example.com$'; +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new('test.' + primary); # NOT OK, but not detected + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new('test.' + 'example.com$'); # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + Regexp.new('^http://test\.example.com'); # NOT OK +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + /^http:\/\/(..|...)\.example\.com\/index\.html/; # OK, wildcards are intentional +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + /^http:\/\/.\.example\.com\/index\.html/; # OK, the wildcard is intentional +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + /^(foo.example\.com|whatever)$/; # kinda OK - one disjunction doesn't even look like a hostname +# {/fact} +end + +def id(e); return e; end +def convert1(domain) + return Regexp.new(domain[:hostname]); +end +def convert2(domain) + return Regexp.new(domain[:hostname]); +end diff --git a/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.expected b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.expected new file mode 100644 index 0000000..a99b3d6 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.expected @@ -0,0 +1,25 @@ +| tst-IncompleteUrlSubstringSanitization.rb:4:5:4:32 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:4:13:4:24 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:5:5:5:32 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:5:13:5:24 | "secure.net" | secure.net | +| tst-IncompleteUrlSubstringSanitization.rb:6:5:6:33 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:6:13:6:25 | ".secure.com" | .secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:10:5:10:33 | ... === ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:10:13:10:24 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:11:5:11:31 | ... === ... | '$@' may be followed by an arbitrary host name. | tst-IncompleteUrlSubstringSanitization.rb:11:13:11:24 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:12:5:12:30 | ... >= ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:12:13:12:24 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:14:5:14:39 | call to start_with? | '$@' may be followed by an arbitrary host name. | tst-IncompleteUrlSubstringSanitization.rb:14:19:14:38 | "https://secure.com" | https://secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:15:5:15:29 | call to end_with? | '$@' may be preceded by an arbitrary host name. | tst-IncompleteUrlSubstringSanitization.rb:15:17:15:28 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:20:5:20:28 | call to include? | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:20:16:20:27 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:32:5:32:40 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:32:13:32:32 | "https://secure.com" | https://secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:33:5:33:44 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:33:13:33:36 | "https://secure.com:443" | https://secure.com:443 | +| tst-IncompleteUrlSubstringSanitization.rb:34:5:34:41 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:34:13:34:33 | "https://secure.com/" | https://secure.com/ | +| tst-IncompleteUrlSubstringSanitization.rb:52:5:52:46 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:52:13:52:38 | "https://example.internal" | https://example.internal | +| tst-IncompleteUrlSubstringSanitization.rb:55:5:55:45 | call to start_with? | '$@' may be followed by an arbitrary host name. | tst-IncompleteUrlSubstringSanitization.rb:55:19:55:44 | "https://example.internal" | https://example.internal | +| tst-IncompleteUrlSubstringSanitization.rb:56:5:56:48 | ... != ... | '$@' may be followed by an arbitrary host name. | tst-IncompleteUrlSubstringSanitization.rb:56:13:56:42 | "https://example.internal.org" | https://example.internal.org | +| tst-IncompleteUrlSubstringSanitization.rb:57:5:57:49 | ... === ... | '$@' may be followed by an arbitrary host name. | tst-IncompleteUrlSubstringSanitization.rb:57:13:57:42 | "https://example.internal.org" | https://example.internal.org | +| tst-IncompleteUrlSubstringSanitization.rb:58:5:58:31 | call to end_with? | '$@' may be preceded by an arbitrary host name. | tst-IncompleteUrlSubstringSanitization.rb:58:17:58:30 | "internal.com" | internal.com | +| tst-IncompleteUrlSubstringSanitization.rb:61:2:61:29 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:61:10:61:21 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:62:2:62:30 | ... === ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:62:10:62:21 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:63:4:63:31 | ... != ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:63:12:63:23 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:64:3:64:26 | call to include? | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:64:14:64:25 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:66:6:66:29 | call to include? | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:66:17:66:28 | "secure.com" | secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:73:5:73:46 | ... >= ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:73:13:73:40 | "https://secure.com/foo/bar" | https://secure.com/foo/bar | +| tst-IncompleteUrlSubstringSanitization.rb:74:5:74:38 | ... >= ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:74:13:74:32 | "https://secure.com" | https://secure.com | +| tst-IncompleteUrlSubstringSanitization.rb:75:5:75:50 | ... >= ... | '$@' can be anywhere in the URL, and arbitrary hosts may come before or after it. | tst-IncompleteUrlSubstringSanitization.rb:75:13:75:44 | "https://secure.com/foo/bar-baz" | https://secure.com/foo/bar-baz | diff --git a/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref new file mode 100644 index 0000000..dea02dc --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/IncompleteUrlSubstringSanitization.qlref @@ -0,0 +1 @@ +queries/security/cwe-020/IncompleteUrlSubstringSanitization.ql diff --git a/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb new file mode 100644 index 0000000..08ce881 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/IncompleteUrlSubstringSanitization/tst-IncompleteUrlSubstringSanitization.rb @@ -0,0 +1,314 @@ +def test (x) +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("internal") != nil; # NOT OK, but not flagged + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("localhost") != nil; # NOT OK, but not flagged + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("secure.com") != nil; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("secure.net") != nil; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index(".secure.com") != nil; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("sub.secure.") != nil; # NOT OK, but not flagged + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index(".sub.secure.") != nil; # NOT OK, but not flagged + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("secure.com") === nil; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("secure.com") === 0; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("secure.com") >= 0; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.start_with?("https://secure.com"); # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.end_with?("secure.com"); # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.end_with?(".secure.com"); # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.start_with?("secure.com/"); # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("secure.com/") === 0; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.include?("secure.com"); # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("#") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index(":") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index(":/") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("://") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("//") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index(":443") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("/some/path/") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("some/path") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("/index.html") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index(":template:") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("https://secure.com") != nil; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("https://secure.com:443") != nil; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("https://secure.com/") != nil; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index(".cn") != nil; # NOT OK, but not flagged + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index(".jpg") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("index.html") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("index.js") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("index.php") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("index.css") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + + x.index("secure=true") != nil; # OK (query param) + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("&auth=") != nil; # OK (query param) + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index(getCurrentDomain()) != nil; # NOT OK, but not flagged + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index(location.origin) != nil; # NOT OK, but not flagged + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("tar.gz") + offset; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("tar.gz") - offset; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("https://example.internal") != nil; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("https://") != nil; # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.start_with?("https://example.internal"); # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index('https://example.internal.org') != 0; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index('https://example.internal.org') === 0; # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.end_with?("internal.com"); # NOT OK + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.start_with?("https://example.internal:80"); # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("secure.com") != nil; # NOT OK + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.index("secure.com") === nil; # OK + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + !(x.index("secure.com") != nil); # OK + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + + !x.include?("secure.com"); # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + if !x.include?("secure.com") # NOT OK + +# {/fact} + + else + doSomeThingWithTrustedURL(x); + end + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + x.start_with?("https://secure.com/foo/bar"); # OK - a forward slash after the domain makes prefix checks safe. + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("https://secure.com/foo/bar") >= 0 # NOT OK - the url can be anywhere in the string. + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("https://secure.com") >= 0 # NOT OK + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + + x.index("https://secure.com/foo/bar-baz") >= 0 # NOT OK - the url can be anywhere in the string. + +# {/fact} +end diff --git a/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/MissingFullAnchor.expected b/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/MissingFullAnchor.expected new file mode 100644 index 0000000..f9b1241 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/MissingFullAnchor.expected @@ -0,0 +1,16 @@ +edges +| impl/miss-anchor.rb:2:12:2:15 | name | impl/miss-anchor.rb:3:39:3:42 | name | +| impl/miss-anchor.rb:6:12:6:15 | name | impl/miss-anchor.rb:7:43:7:46 | name | +| impl/miss-anchor.rb:14:12:14:15 | name | impl/miss-anchor.rb:15:47:15:50 | name | +nodes +| impl/miss-anchor.rb:2:12:2:15 | name | semmle.label | name | +| impl/miss-anchor.rb:3:39:3:42 | name | semmle.label | name | +| impl/miss-anchor.rb:6:12:6:15 | name | semmle.label | name | +| impl/miss-anchor.rb:7:43:7:46 | name | semmle.label | name | +| impl/miss-anchor.rb:14:12:14:15 | name | semmle.label | name | +| impl/miss-anchor.rb:15:47:15:50 | name | semmle.label | name | +subpaths +#select +| impl/miss-anchor.rb:3:39:3:42 | name | impl/miss-anchor.rb:2:12:2:15 | name | impl/miss-anchor.rb:3:39:3:42 | name | This value depends on $@, and is $@ against a $@. | impl/miss-anchor.rb:2:12:2:15 | name | library input | impl/miss-anchor.rb:3:39:3:89 | ... !~ ... | checked | impl/miss-anchor.rb:3:48:3:88 | ^[A-Za-z0-9\\+\\-_]+(\\/[A-Za-z0-9\\+\\-_]+)*$ | badly anchored regular expression | +| impl/miss-anchor.rb:7:43:7:46 | name | impl/miss-anchor.rb:6:12:6:15 | name | impl/miss-anchor.rb:7:43:7:46 | name | This value depends on $@, and is $@ against a $@. | impl/miss-anchor.rb:6:12:6:15 | name | library input | impl/miss-anchor.rb:7:43:7:93 | ... !~ ... | checked | impl/miss-anchor.rb:7:52:7:92 | ^[A-Za-z0-9\\+\\-_]+(\\/[A-Za-z0-9\\+\\-_]+)*$ | badly anchored regular expression | +| impl/miss-anchor.rb:15:47:15:50 | name | impl/miss-anchor.rb:14:12:14:15 | name | impl/miss-anchor.rb:15:47:15:50 | name | This value depends on $@, and is $@ against a $@. | impl/miss-anchor.rb:14:12:14:15 | name | library input | impl/miss-anchor.rb:15:47:15:97 | ... !~ ... | checked | impl/miss-anchor.rb:15:56:15:96 | ^[A-Za-z0-9\\+\\-_]+(\\/[A-Za-z0-9\\+\\-_]+)*$ | badly anchored regular expression | diff --git a/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/MissingFullAnchor.qlref b/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/MissingFullAnchor.qlref new file mode 100644 index 0000000..4b61fcc --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/MissingFullAnchor.qlref @@ -0,0 +1 @@ +queries/security/cwe-020/MissingFullAnchor.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/impl/miss-anchor.rb b/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/impl/miss-anchor.rb new file mode 100644 index 0000000..2082042 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/impl/miss-anchor.rb @@ -0,0 +1,32 @@ +class Foobar +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + def foo1(name) + + raise Blabity, 'Invalid thing' if name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK + + end +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + def foo2(name) + + raise Blabity, 'Invalid thing' unless name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK + + end +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + def foo3(name) + raise Blabity, 'Invalid thing' unless name !~ /\A[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*\z/ # OK + + end +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + def foo4(name) + + raise Blabity, 'Invalid thing' unless not name !~ /^[A-Za-z0-9\+\-_]+(\/[A-Za-z0-9\+\-_]+)*$/ # NOT OK + + end +# {/fact} +end diff --git a/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/miss-anchor.gemspec b/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/miss-anchor.gemspec new file mode 100644 index 0000000..0295558 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/MissingFullAnchor/miss-anchor.gemspec @@ -0,0 +1,5 @@ +Gem::Specification.new do |s| + s.name = 'miss-anchor' + s.require_path = "impl" +end + \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.expected b/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.expected new file mode 100644 index 0000000..58e95fb --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.expected @@ -0,0 +1,20 @@ +| missing_regexp_anchor.rb:1:1:1:19 | /www\\.example\\.com/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | +| missing_regexp_anchor.rb:7:1:7:22 | /https?:\\/\\/good\\.com/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | +| missing_regexp_anchor.rb:8:1:8:23 | /^https?:\\/\\/good\\.com/ | This hostname pattern may match any domain name, as it is missing a '\\z' or '/' at the end. | +| missing_regexp_anchor.rb:19:1:19:6 | /^a\|b/ | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:22:1:22:8 | /^a\|b\|c/ | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:28:1:28:8 | /^a\|(b)/ | Misleading operator precedence. The subexpression '^a' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:30:1:30:10 | /^(a)\|(b)/ | Misleading operator precedence. The subexpression '^(a)' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:33:1:33:6 | /a\|b$/ | Misleading operator precedence. The subexpression 'b$' is anchored at the end, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:36:1:36:8 | /a\|b\|c$/ | Misleading operator precedence. The subexpression 'c$' is anchored at the end, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:42:1:42:8 | /(a)\|b$/ | Misleading operator precedence. The subexpression 'b$' is anchored at the end, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:44:1:44:10 | /(a)\|(b)$/ | Misleading operator precedence. The subexpression '(b)$' is anchored at the end, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:46:1:46:22 | /^good.com\|better.com/ | Misleading operator precedence. The subexpression '^good.com' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:47:1:47:24 | /^good\\.com\|better\\.com/ | Misleading operator precedence. The subexpression '^good\\.com' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:48:1:48:26 | /^good\\\\.com\|better\\\\.com/ | Misleading operator precedence. The subexpression '^good\\\\.com' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:49:1:49:28 | /^good\\\\\\.com\|better\\\\\\.com/ | Misleading operator precedence. The subexpression '^good\\\\\\.com' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:50:1:50:30 | /^good\\\\\\\\.com\|better\\\\\\\\.com/ | Misleading operator precedence. The subexpression '^good\\\\\\\\.com' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:52:1:52:15 | /^foo\|bar\|baz$/ | Misleading operator precedence. The subexpression '^foo' is anchored at the beginning, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:52:1:52:15 | /^foo\|bar\|baz$/ | Misleading operator precedence. The subexpression 'baz$' is anchored at the end, but the other parts of this regular expression are not | +| missing_regexp_anchor.rb:60:20:60:39 | "http://example.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | +| missing_regexp_anchor.rb:61:19:61:38 | "http://example.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. | diff --git a/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.qlref b/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.qlref new file mode 100644 index 0000000..bd3ad56 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/MissingRegExpAnchor.qlref @@ -0,0 +1 @@ +queries/security/cwe-020/MissingRegExpAnchor.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/missing_regexp_anchor.rb b/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/missing_regexp_anchor.rb new file mode 100644 index 0000000..42e3043 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/MissingRegExpAnchor/missing_regexp_anchor.rb @@ -0,0 +1,193 @@ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/www\.example\.com/ # BAD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^www\.example\.com$/ # BAD: uses end-of-line anchors rather than end-of-string anchors + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +/\Awww\.example\.com\z/ # GOOD + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +/foo\.bar/ # GOOD + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/https?:\/\/good\.com/ # BAD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^https?:\/\/good\.com/ # BAD: missing end-of-string anchor + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/(^https?:\/\/good1\.com)|(^https?:#good2\.com)/ # BAD: missing end-of-string anchor + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +/bar/ # GOOD + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +foo.gsub(/www\.example\.com/, "bar") # GOOD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +foo.sub(/www\.example.com/, "bar") # GOOD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +foo.gsub!(/www\.example\.com/, "bar") # GOOD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +foo.sub!(/www\.example\.com/, "bar") # GOOD + +# {/fact} + +/^a|/ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^a|b/ # BAD + +# {/fact} +/a|^b/ +/^a|^b/ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^a|b|c/ # BAD + +# {/fact} +/a|^b|c/ +/a|b|^c/ +/^a|^b|c/ + +/(^a)|b/ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^a|(b)/ # BAD + +# {/fact} +/^a|(^b)/ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^(a)|(b)/ # BAD + +# {/fact} + + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/a|b$/ # BAD + +# {/fact} +/a$|b/ +/a$|b$/ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/a|b|c$/ # BAD + +# {/fact} +/a|b$|c/ +/a$|b|c/ +/a|b$|c$/ + +/a|(b$)/ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/(a)|b$/ # BAD + +# {/fact} +/(a$)|b$/ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/(a)|(b)$/ # BAD + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^good.com|better.com/ # BAD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^good\.com|better\.com/ # BAD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^good\\.com|better\\.com/ # BAD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^good\\\.com|better\\\.com/ # BAD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^good\\\\.com|better\\\\.com/ # BAD + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +/^foo|bar|baz$/ # BAD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +/^foo|%/ # OK + +# {/fact} + +REGEXP = /foo/ +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +REGEXP.match? "http://example.com" # GOOD: the url is the text not the regexp + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +REGEXP.match "http://example.com" # GOOD: the url is the text not the regexp + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +"http://example.com".match? REGEXP # GOOD: the url is the text not the regexp + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +"http://example.com".match REGEXP # GOOD: the url is the text not the regexp + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +"some text".match? "http://example.com" # BAD + +# {/fact} +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +"some text".match "http://example.com" # BAD + +# {/fact} diff --git a/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.expected b/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.expected new file mode 100644 index 0000000..6eefe94 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.expected @@ -0,0 +1,11 @@ +| suspicous_regexp_range.rb:1:15:1:17 | 0-9 | Suspicious character range that overlaps with 3-5 in the same character class. | +| suspicous_regexp_range.rb:3:17:3:19 | A-z | Suspicious character range that overlaps with A-Z in the same character class, and is equivalent to [A-Z\\[\\\\\\]^_`a-z]. | +| suspicous_regexp_range.rb:5:14:5:16 | z-a | Suspicious character range that is empty. | +| suspicous_regexp_range.rb:15:24:15:26 | A-f | Suspicious character range that overlaps with a-f in the same character class, and is equivalent to [A-Z\\[\\\\\\]^_`a-f]. | +| suspicous_regexp_range.rb:17:16:17:18 | $-` | Suspicious character range that is equivalent to [$%&'()*+,\\-.\\/0-9:;<=>?@A-Z\\[\\\\\\]^_`]. | +| suspicous_regexp_range.rb:19:29:19:31 | +-< | Suspicious character range that is equivalent to [+,\\-.\\/0-9:;<]. | +| suspicous_regexp_range.rb:21:33:21:35 | .-_ | Suspicious character range that overlaps with 1-9 in the same character class, and is equivalent to [.\\/0-9:;<=>?@A-Z\\[\\\\\\]^_]. | +| suspicous_regexp_range.rb:23:20:23:22 | 7-F | Suspicious character range that is equivalent to [7-9:;<=>?@A-F]. | +| suspicous_regexp_range.rb:25:24:25:26 | 0-9 | Suspicious character range that overlaps with \\d in the same character class. | +| suspicous_regexp_range.rb:27:27:27:29 | .-? | Suspicious character range that overlaps with \\w in the same character class, and is equivalent to [.\\/0-9:;<=>?]. | +| suspicous_regexp_range.rb:33:28:33:30 | %-. | Suspicious character range that is equivalent to [%&'()*+,\\-.]. | diff --git a/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref b/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref new file mode 100644 index 0000000..f1d6eea --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/OverlyLargeRangeQuery.qlref @@ -0,0 +1 @@ +queries/security/cwe-020/OverlyLargeRange.ql diff --git a/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/suspicous_regexp_range.rb b/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/suspicous_regexp_range.rb new file mode 100644 index 0000000..9d72833 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-020/SuspiciousRegexpRange/suspicous_regexp_range.rb @@ -0,0 +1,97 @@ +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +overlap1 = /^[0-93-5]$/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +overlap2 = /[A-ZA-z]/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +isEmpty = /^[z-a]$/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +isAscii = /^[\x00-\x7F]*$/ # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +printable = /[!-~]/ # OK - used to select most printable ASCII characters + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +codePoints = /[^\x21-\x7E]|[\[\](){}<>\/%]/ # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/ # OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +smallOverlap = /[0-9a-fA-f]/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +weirdRange = /[$-`]/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +keywordOperator = /[!\~\*\/%+-<>\^|=&]/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +notYoutube = /youtu\.be\/[a-z1-9.-_]+/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +numberToLetter = /[7-F]/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +overlapsWithClass1 = /[0-9\d]/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=1} + +overlapsWithClass2 = /[\w,.-?:*+]/ # NOT OK + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +escapes = /[\000-\037\047\134\177-\377]/n # OK - they are escapes + +# {/fact} + +# {fact rule=cryptographic-key-generator@v1.0 defects=0} + +nested = /[a-z&&[^a-c]]/ # OK + +# {/fact} + +overlapsWithNothing = /[\w_%-.]/; \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-022/ArchiveApiPathTraversal.rb b/PR_10_ruby/codeql_ruby/cwe-022/ArchiveApiPathTraversal.rb new file mode 100644 index 0000000..b714d42 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-022/ArchiveApiPathTraversal.rb @@ -0,0 +1,95 @@ +class TestContoller < ActionController::Base +# {fact rule=client-constructor-deprecated-rule@v1.0 defects=1} + # this is vulnerable + def upload + untar params[:file], params[:filename] + end +# {/fact} + +# {fact rule=client-constructor-deprecated-rule@v1.0 defects=1} + # this is vulnerable + def unpload_zip + unzip params[:file] + end +# {/fact} + +# {fact rule=client-constructor-deprecated-rule@v1.0 defects=1} + # this is vulnerable + def create_new_zip + zip params[:filename], files + end +# {/fact} + +# {fact rule=client-constructor-deprecated-rule@v1.0 defects=0} + # these are not vulnerable because of the string compare sanitizer + def safe_upload_string_compare + filename = params[:filename] + if filename == "safefile.tar" + untar params[:file], filename + end + end +# {/fact} + +# {fact rule=client-constructor-deprecated-rule@v1.0 defects=0} + def safe_upload_zip_string_compare + filename = params[:filename] + if filename == "safefile.zip" + unzip filename + end + end +# {/fact} + +# {fact rule=client-constructor-deprecated-rule@v1.0 defects=0} + # these are not vulnerable beacuse of the string array compare sanitizer + def safe_upload_string_array_compare + filename = params[:filename] + if ["safefile1.tar", "safefile2.tar"].include? filename + untar params[:file], filename + end + end +# {/fact} + +# {fact rule=client-constructor-deprecated-rule@v1.0 defects=0} + def safe_upload_zip_string_array_compare + filename = params[:filename] + if ["safefile1.zip", "safefile2.zip"].include? filename + unzip filename + end + end +# {/fact} + + # these are our two sinks + def untar(io, destination) + Gem::Package::TarReader.new io do |tar| + tar.each do |tarfile| + destination_file = File.join destination, tarfile.full_name + + if tarfile.directory? + FileUtils.mkdir_p destination_file + else + destination_directory = File.dirname(destination_file) + FileUtils.mkdir_p destination_directory unless File.directory?(destination_directory) + File.open destination_file, "wb" do |f| + f.print tarfile.read + end + end + end + end + end + + def unzip(file) + Zip::File.open(file) do |zip_file| + zip_file.each do |entry| + entry.extract + end + end + end + + def zip(filename, files = []) + Zip::File.new(filename) do |zf| + files.each do |f| + zf.add f + end + end + end +end \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-022/PathInjection.expected b/PR_10_ruby/codeql_ruby/cwe-022/PathInjection.expected new file mode 100644 index 0000000..7ee24c4 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-022/PathInjection.expected @@ -0,0 +1,168 @@ +edges +| ArchiveApiPathTraversal.rb:5:26:5:31 | call to params | ArchiveApiPathTraversal.rb:5:26:5:42 | ...[...] | +| ArchiveApiPathTraversal.rb:5:26:5:42 | ...[...] | ArchiveApiPathTraversal.rb:49:17:49:27 | destination | +| ArchiveApiPathTraversal.rb:10:11:10:16 | call to params | ArchiveApiPathTraversal.rb:10:11:10:23 | ...[...] | +| ArchiveApiPathTraversal.rb:10:11:10:23 | ...[...] | ArchiveApiPathTraversal.rb:67:13:67:16 | file | +| ArchiveApiPathTraversal.rb:15:9:15:14 | call to params | ArchiveApiPathTraversal.rb:15:9:15:25 | ...[...] | +| ArchiveApiPathTraversal.rb:15:9:15:25 | ...[...] | ArchiveApiPathTraversal.rb:75:11:75:18 | filename | +| ArchiveApiPathTraversal.rb:49:17:49:27 | destination | ArchiveApiPathTraversal.rb:52:38:52:48 | destination | +| ArchiveApiPathTraversal.rb:52:9:52:24 | destination_file | ArchiveApiPathTraversal.rb:59:21:59:36 | destination_file | +| ArchiveApiPathTraversal.rb:52:28:52:67 | call to join | ArchiveApiPathTraversal.rb:52:9:52:24 | destination_file | +| ArchiveApiPathTraversal.rb:52:38:52:48 | destination | ArchiveApiPathTraversal.rb:52:28:52:67 | call to join | +| ArchiveApiPathTraversal.rb:67:13:67:16 | file | ArchiveApiPathTraversal.rb:68:20:68:23 | file | +| ArchiveApiPathTraversal.rb:75:11:75:18 | filename | ArchiveApiPathTraversal.rb:76:19:76:26 | filename | +| tainted_path.rb:4:5:4:8 | path | tainted_path.rb:5:26:5:29 | path | +| tainted_path.rb:4:12:4:17 | call to params | tainted_path.rb:4:12:4:24 | ...[...] | +| tainted_path.rb:4:12:4:24 | ...[...] | tainted_path.rb:4:5:4:8 | path | +| tainted_path.rb:10:5:10:8 | path | tainted_path.rb:11:26:11:29 | path | +| tainted_path.rb:10:12:10:43 | call to absolute_path | tainted_path.rb:10:5:10:8 | path | +| tainted_path.rb:10:31:10:36 | call to params | tainted_path.rb:10:31:10:43 | ...[...] | +| tainted_path.rb:10:31:10:43 | ...[...] | tainted_path.rb:10:12:10:43 | call to absolute_path | +| tainted_path.rb:16:5:16:8 | path | tainted_path.rb:17:26:17:29 | path | +| tainted_path.rb:16:15:16:41 | call to dirname | tainted_path.rb:16:5:16:8 | path | +| tainted_path.rb:16:28:16:33 | call to params | tainted_path.rb:16:28:16:40 | ...[...] | +| tainted_path.rb:16:28:16:40 | ...[...] | tainted_path.rb:16:15:16:41 | call to dirname | +| tainted_path.rb:22:5:22:8 | path | tainted_path.rb:23:26:23:29 | path | +| tainted_path.rb:22:12:22:41 | call to expand_path | tainted_path.rb:22:5:22:8 | path | +| tainted_path.rb:22:29:22:34 | call to params | tainted_path.rb:22:29:22:41 | ...[...] | +| tainted_path.rb:22:29:22:41 | ...[...] | tainted_path.rb:22:12:22:41 | call to expand_path | +| tainted_path.rb:28:5:28:8 | path | tainted_path.rb:29:26:29:29 | path | +| tainted_path.rb:28:12:28:34 | call to path | tainted_path.rb:28:5:28:8 | path | +| tainted_path.rb:28:22:28:27 | call to params | tainted_path.rb:28:22:28:34 | ...[...] | +| tainted_path.rb:28:22:28:34 | ...[...] | tainted_path.rb:28:12:28:34 | call to path | +| tainted_path.rb:34:5:34:8 | path | tainted_path.rb:35:26:35:29 | path | +| tainted_path.rb:34:12:34:41 | call to realdirpath | tainted_path.rb:34:5:34:8 | path | +| tainted_path.rb:34:29:34:34 | call to params | tainted_path.rb:34:29:34:41 | ...[...] | +| tainted_path.rb:34:29:34:41 | ...[...] | tainted_path.rb:34:12:34:41 | call to realdirpath | +| tainted_path.rb:40:5:40:8 | path | tainted_path.rb:41:26:41:29 | path | +| tainted_path.rb:40:12:40:38 | call to realpath | tainted_path.rb:40:5:40:8 | path | +| tainted_path.rb:40:26:40:31 | call to params | tainted_path.rb:40:26:40:38 | ...[...] | +| tainted_path.rb:40:26:40:38 | ...[...] | tainted_path.rb:40:12:40:38 | call to realpath | +| tainted_path.rb:47:5:47:8 | path | tainted_path.rb:48:26:48:29 | path | +| tainted_path.rb:47:12:47:63 | call to join | tainted_path.rb:47:5:47:8 | path | +| tainted_path.rb:47:43:47:48 | call to params | tainted_path.rb:47:43:47:55 | ...[...] | +| tainted_path.rb:47:43:47:55 | ...[...] | tainted_path.rb:47:12:47:63 | call to join | +| tainted_path.rb:59:5:59:8 | path | tainted_path.rb:60:26:60:29 | path | +| tainted_path.rb:59:12:59:53 | call to new | tainted_path.rb:59:5:59:8 | path | +| tainted_path.rb:59:40:59:45 | call to params | tainted_path.rb:59:40:59:52 | ...[...] | +| tainted_path.rb:59:40:59:52 | ...[...] | tainted_path.rb:59:12:59:53 | call to new | +| tainted_path.rb:71:5:71:8 | path | tainted_path.rb:72:15:72:18 | path | +| tainted_path.rb:71:12:71:53 | call to new | tainted_path.rb:71:5:71:8 | path | +| tainted_path.rb:71:40:71:45 | call to params | tainted_path.rb:71:40:71:52 | ...[...] | +| tainted_path.rb:71:40:71:52 | ...[...] | tainted_path.rb:71:12:71:53 | call to new | +| tainted_path.rb:77:5:77:8 | path | tainted_path.rb:78:19:78:22 | path | +| tainted_path.rb:77:5:77:8 | path | tainted_path.rb:79:14:79:17 | path | +| tainted_path.rb:77:12:77:53 | call to new | tainted_path.rb:77:5:77:8 | path | +| tainted_path.rb:77:40:77:45 | call to params | tainted_path.rb:77:40:77:52 | ...[...] | +| tainted_path.rb:77:40:77:52 | ...[...] | tainted_path.rb:77:12:77:53 | call to new | +| tainted_path.rb:84:5:84:8 | path | tainted_path.rb:85:10:85:13 | path | +| tainted_path.rb:84:5:84:8 | path | tainted_path.rb:86:25:86:28 | path | +| tainted_path.rb:84:12:84:53 | call to new | tainted_path.rb:84:5:84:8 | path | +| tainted_path.rb:84:40:84:45 | call to params | tainted_path.rb:84:40:84:52 | ...[...] | +| tainted_path.rb:84:40:84:52 | ...[...] | tainted_path.rb:84:12:84:53 | call to new | +| tainted_path.rb:90:5:90:8 | path | tainted_path.rb:92:11:92:14 | path | +| tainted_path.rb:90:12:90:53 | call to new | tainted_path.rb:90:5:90:8 | path | +| tainted_path.rb:90:40:90:45 | call to params | tainted_path.rb:90:40:90:52 | ...[...] | +| tainted_path.rb:90:40:90:52 | ...[...] | tainted_path.rb:90:12:90:53 | call to new | +nodes +| ArchiveApiPathTraversal.rb:5:26:5:31 | call to params | semmle.label | call to params | +| ArchiveApiPathTraversal.rb:5:26:5:42 | ...[...] | semmle.label | ...[...] | +| ArchiveApiPathTraversal.rb:10:11:10:16 | call to params | semmle.label | call to params | +| ArchiveApiPathTraversal.rb:10:11:10:23 | ...[...] | semmle.label | ...[...] | +| ArchiveApiPathTraversal.rb:15:9:15:14 | call to params | semmle.label | call to params | +| ArchiveApiPathTraversal.rb:15:9:15:25 | ...[...] | semmle.label | ...[...] | +| ArchiveApiPathTraversal.rb:49:17:49:27 | destination | semmle.label | destination | +| ArchiveApiPathTraversal.rb:52:9:52:24 | destination_file | semmle.label | destination_file | +| ArchiveApiPathTraversal.rb:52:28:52:67 | call to join | semmle.label | call to join | +| ArchiveApiPathTraversal.rb:52:38:52:48 | destination | semmle.label | destination | +| ArchiveApiPathTraversal.rb:59:21:59:36 | destination_file | semmle.label | destination_file | +| ArchiveApiPathTraversal.rb:67:13:67:16 | file | semmle.label | file | +| ArchiveApiPathTraversal.rb:68:20:68:23 | file | semmle.label | file | +| ArchiveApiPathTraversal.rb:75:11:75:18 | filename | semmle.label | filename | +| ArchiveApiPathTraversal.rb:76:19:76:26 | filename | semmle.label | filename | +| tainted_path.rb:4:5:4:8 | path | semmle.label | path | +| tainted_path.rb:4:12:4:17 | call to params | semmle.label | call to params | +| tainted_path.rb:4:12:4:24 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:5:26:5:29 | path | semmle.label | path | +| tainted_path.rb:10:5:10:8 | path | semmle.label | path | +| tainted_path.rb:10:12:10:43 | call to absolute_path | semmle.label | call to absolute_path | +| tainted_path.rb:10:31:10:36 | call to params | semmle.label | call to params | +| tainted_path.rb:10:31:10:43 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:11:26:11:29 | path | semmle.label | path | +| tainted_path.rb:16:5:16:8 | path | semmle.label | path | +| tainted_path.rb:16:15:16:41 | call to dirname | semmle.label | call to dirname | +| tainted_path.rb:16:28:16:33 | call to params | semmle.label | call to params | +| tainted_path.rb:16:28:16:40 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:17:26:17:29 | path | semmle.label | path | +| tainted_path.rb:22:5:22:8 | path | semmle.label | path | +| tainted_path.rb:22:12:22:41 | call to expand_path | semmle.label | call to expand_path | +| tainted_path.rb:22:29:22:34 | call to params | semmle.label | call to params | +| tainted_path.rb:22:29:22:41 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:23:26:23:29 | path | semmle.label | path | +| tainted_path.rb:28:5:28:8 | path | semmle.label | path | +| tainted_path.rb:28:12:28:34 | call to path | semmle.label | call to path | +| tainted_path.rb:28:22:28:27 | call to params | semmle.label | call to params | +| tainted_path.rb:28:22:28:34 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:29:26:29:29 | path | semmle.label | path | +| tainted_path.rb:34:5:34:8 | path | semmle.label | path | +| tainted_path.rb:34:12:34:41 | call to realdirpath | semmle.label | call to realdirpath | +| tainted_path.rb:34:29:34:34 | call to params | semmle.label | call to params | +| tainted_path.rb:34:29:34:41 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:35:26:35:29 | path | semmle.label | path | +| tainted_path.rb:40:5:40:8 | path | semmle.label | path | +| tainted_path.rb:40:12:40:38 | call to realpath | semmle.label | call to realpath | +| tainted_path.rb:40:26:40:31 | call to params | semmle.label | call to params | +| tainted_path.rb:40:26:40:38 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:41:26:41:29 | path | semmle.label | path | +| tainted_path.rb:47:5:47:8 | path | semmle.label | path | +| tainted_path.rb:47:12:47:63 | call to join | semmle.label | call to join | +| tainted_path.rb:47:43:47:48 | call to params | semmle.label | call to params | +| tainted_path.rb:47:43:47:55 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:48:26:48:29 | path | semmle.label | path | +| tainted_path.rb:59:5:59:8 | path | semmle.label | path | +| tainted_path.rb:59:12:59:53 | call to new | semmle.label | call to new | +| tainted_path.rb:59:40:59:45 | call to params | semmle.label | call to params | +| tainted_path.rb:59:40:59:52 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:60:26:60:29 | path | semmle.label | path | +| tainted_path.rb:71:5:71:8 | path | semmle.label | path | +| tainted_path.rb:71:12:71:53 | call to new | semmle.label | call to new | +| tainted_path.rb:71:40:71:45 | call to params | semmle.label | call to params | +| tainted_path.rb:71:40:71:52 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:72:15:72:18 | path | semmle.label | path | +| tainted_path.rb:77:5:77:8 | path | semmle.label | path | +| tainted_path.rb:77:12:77:53 | call to new | semmle.label | call to new | +| tainted_path.rb:77:40:77:45 | call to params | semmle.label | call to params | +| tainted_path.rb:77:40:77:52 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:78:19:78:22 | path | semmle.label | path | +| tainted_path.rb:79:14:79:17 | path | semmle.label | path | +| tainted_path.rb:84:5:84:8 | path | semmle.label | path | +| tainted_path.rb:84:12:84:53 | call to new | semmle.label | call to new | +| tainted_path.rb:84:40:84:45 | call to params | semmle.label | call to params | +| tainted_path.rb:84:40:84:52 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:85:10:85:13 | path | semmle.label | path | +| tainted_path.rb:86:25:86:28 | path | semmle.label | path | +| tainted_path.rb:90:5:90:8 | path | semmle.label | path | +| tainted_path.rb:90:12:90:53 | call to new | semmle.label | call to new | +| tainted_path.rb:90:40:90:45 | call to params | semmle.label | call to params | +| tainted_path.rb:90:40:90:52 | ...[...] | semmle.label | ...[...] | +| tainted_path.rb:92:11:92:14 | path | semmle.label | path | +subpaths +#select +| ArchiveApiPathTraversal.rb:59:21:59:36 | destination_file | ArchiveApiPathTraversal.rb:5:26:5:31 | call to params | ArchiveApiPathTraversal.rb:59:21:59:36 | destination_file | This path depends on a $@. | ArchiveApiPathTraversal.rb:5:26:5:31 | call to params | user-provided value | +| ArchiveApiPathTraversal.rb:68:20:68:23 | file | ArchiveApiPathTraversal.rb:10:11:10:16 | call to params | ArchiveApiPathTraversal.rb:68:20:68:23 | file | This path depends on a $@. | ArchiveApiPathTraversal.rb:10:11:10:16 | call to params | user-provided value | +| ArchiveApiPathTraversal.rb:76:19:76:26 | filename | ArchiveApiPathTraversal.rb:15:9:15:14 | call to params | ArchiveApiPathTraversal.rb:76:19:76:26 | filename | This path depends on a $@. | ArchiveApiPathTraversal.rb:15:9:15:14 | call to params | user-provided value | +| tainted_path.rb:5:26:5:29 | path | tainted_path.rb:4:12:4:17 | call to params | tainted_path.rb:5:26:5:29 | path | This path depends on a $@. | tainted_path.rb:4:12:4:17 | call to params | user-provided value | +| tainted_path.rb:11:26:11:29 | path | tainted_path.rb:10:31:10:36 | call to params | tainted_path.rb:11:26:11:29 | path | This path depends on a $@. | tainted_path.rb:10:31:10:36 | call to params | user-provided value | +| tainted_path.rb:17:26:17:29 | path | tainted_path.rb:16:28:16:33 | call to params | tainted_path.rb:17:26:17:29 | path | This path depends on a $@. | tainted_path.rb:16:28:16:33 | call to params | user-provided value | +| tainted_path.rb:23:26:23:29 | path | tainted_path.rb:22:29:22:34 | call to params | tainted_path.rb:23:26:23:29 | path | This path depends on a $@. | tainted_path.rb:22:29:22:34 | call to params | user-provided value | +| tainted_path.rb:29:26:29:29 | path | tainted_path.rb:28:22:28:27 | call to params | tainted_path.rb:29:26:29:29 | path | This path depends on a $@. | tainted_path.rb:28:22:28:27 | call to params | user-provided value | +| tainted_path.rb:35:26:35:29 | path | tainted_path.rb:34:29:34:34 | call to params | tainted_path.rb:35:26:35:29 | path | This path depends on a $@. | tainted_path.rb:34:29:34:34 | call to params | user-provided value | +| tainted_path.rb:41:26:41:29 | path | tainted_path.rb:40:26:40:31 | call to params | tainted_path.rb:41:26:41:29 | path | This path depends on a $@. | tainted_path.rb:40:26:40:31 | call to params | user-provided value | +| tainted_path.rb:48:26:48:29 | path | tainted_path.rb:47:43:47:48 | call to params | tainted_path.rb:48:26:48:29 | path | This path depends on a $@. | tainted_path.rb:47:43:47:48 | call to params | user-provided value | +| tainted_path.rb:60:26:60:29 | path | tainted_path.rb:59:40:59:45 | call to params | tainted_path.rb:60:26:60:29 | path | This path depends on a $@. | tainted_path.rb:59:40:59:45 | call to params | user-provided value | +| tainted_path.rb:72:15:72:18 | path | tainted_path.rb:71:40:71:45 | call to params | tainted_path.rb:72:15:72:18 | path | This path depends on a $@. | tainted_path.rb:71:40:71:45 | call to params | user-provided value | +| tainted_path.rb:78:19:78:22 | path | tainted_path.rb:77:40:77:45 | call to params | tainted_path.rb:78:19:78:22 | path | This path depends on a $@. | tainted_path.rb:77:40:77:45 | call to params | user-provided value | +| tainted_path.rb:79:14:79:17 | path | tainted_path.rb:77:40:77:45 | call to params | tainted_path.rb:79:14:79:17 | path | This path depends on a $@. | tainted_path.rb:77:40:77:45 | call to params | user-provided value | +| tainted_path.rb:85:10:85:13 | path | tainted_path.rb:84:40:84:45 | call to params | tainted_path.rb:85:10:85:13 | path | This path depends on a $@. | tainted_path.rb:84:40:84:45 | call to params | user-provided value | +| tainted_path.rb:86:25:86:28 | path | tainted_path.rb:84:40:84:45 | call to params | tainted_path.rb:86:25:86:28 | path | This path depends on a $@. | tainted_path.rb:84:40:84:45 | call to params | user-provided value | +| tainted_path.rb:92:11:92:14 | path | tainted_path.rb:90:40:90:45 | call to params | tainted_path.rb:92:11:92:14 | path | This path depends on a $@. | tainted_path.rb:90:40:90:45 | call to params | user-provided value | diff --git a/PR_10_ruby/codeql_ruby/cwe-022/PathInjection.qlref b/PR_10_ruby/codeql_ruby/cwe-022/PathInjection.qlref new file mode 100644 index 0000000..7b98278 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-022/PathInjection.qlref @@ -0,0 +1 @@ +queries/security/cwe-022/PathInjection.ql diff --git a/PR_10_ruby/codeql_ruby/cwe-022/tainted_path.rb b/PR_10_ruby/codeql_ruby/cwe-022/tainted_path.rb new file mode 100644 index 0000000..44b2217 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-022/tainted_path.rb @@ -0,0 +1,159 @@ +class FooController < ActionController::Base +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD + + + def route0 + path = params[:path] + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD - File.absolute_path preserves taint + + + def route1 + path = File.absolute_path params[:path] + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD - File.dirname preserves taint + + + def route2 + path = "#{File.dirname(params[:path])}/foo" + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD - File.expand_path preserves taint + + + def route3 + path = File.expand_path params[:path] + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD - File.path preserves taint + + + def route4 + path = File.path params[:path] + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD - File.realdirpath preserves taint + + + def route5 + path = File.realdirpath params[:path] + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD - File.realpath preserves taint + + + def route6 + path = File.realpath params[:path] + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD - tainted arguments in any position propagate to the return value of + + + # File.join + def route7 + path = File.join("foo", "bar", "baz", params[:path], "qux") + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=0} + + # GOOD - File.basename does not preserve taint + + + def route8 + path = File.basename params[:path] + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD + + def route9 + path = ActiveStorage::Filename.new(params[:path]) + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=0} + + # GOOD - explicitly sanitized + + def route10 + path = ActiveStorage::Filename.new(params[:path]).sanitized + @content = File.read path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD + + def route11 + path = ActiveStorage::Filename.new(params[:path]) + send_file path + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD + + def route12 + path = ActiveStorage::Filename.new(params[:path]) + bla (Dir.glob path) + bla (Dir[path]) + end +# {/fact} + +# {fact rule=path-traversal@v1.0 defects=1} + + # BAD + + def route13 + path = ActiveStorage::Filename.new(params[:path]) + load(path) + autoload(:MyModule, path) + end + + def require_relative() + path = ActiveStorage::Filename.new(params[:path]) + puts "Debug: require_relative(#{path})" + super(path) + end +end +# {/fact} \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.expected b/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.expected new file mode 100644 index 0000000..ba0fef8 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.expected @@ -0,0 +1,73 @@ +edges +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:7:10:7:15 | #{...} | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:8:16:8:18 | cmd | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:10:14:10:16 | cmd | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:11:17:11:22 | #{...} | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:13:9:13:14 | #{...} | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:29:19:29:24 | #{...} | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:33:24:33:36 | "echo #{...}" | +| CommandInjection.rb:6:9:6:11 | cmd | CommandInjection.rb:34:39:34:51 | "grep #{...}" | +| CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:6:15:6:26 | ...[...] | +| CommandInjection.rb:6:15:6:26 | ...[...] | CommandInjection.rb:6:9:6:11 | cmd | +| CommandInjection.rb:46:9:46:11 | cmd | CommandInjection.rb:50:24:50:36 | "echo #{...}" | +| CommandInjection.rb:46:15:46:20 | call to params | CommandInjection.rb:46:15:46:26 | ...[...] | +| CommandInjection.rb:46:15:46:26 | ...[...] | CommandInjection.rb:46:9:46:11 | cmd | +| CommandInjection.rb:54:7:54:9 | cmd | CommandInjection.rb:59:14:59:16 | cmd | +| CommandInjection.rb:54:13:54:18 | call to params | CommandInjection.rb:54:13:54:24 | ...[...] | +| CommandInjection.rb:54:13:54:24 | ...[...] | CommandInjection.rb:54:7:54:9 | cmd | +| CommandInjection.rb:73:18:73:23 | number | CommandInjection.rb:74:14:74:29 | "echo #{...}" | +| CommandInjection.rb:81:23:81:33 | blah_number | CommandInjection.rb:82:14:82:34 | "echo #{...}" | +| CommandInjection.rb:90:20:90:25 | **args | CommandInjection.rb:91:22:91:25 | args | +| CommandInjection.rb:91:22:91:25 | args | CommandInjection.rb:91:22:91:37 | ...[...] | +| CommandInjection.rb:91:22:91:37 | ...[...] | CommandInjection.rb:91:14:91:39 | "echo #{...}" | +| CommandInjection.rb:103:9:103:12 | file | CommandInjection.rb:104:16:104:28 | "cat #{...}" | +| CommandInjection.rb:103:16:103:21 | call to params | CommandInjection.rb:103:16:103:28 | ...[...] | +| CommandInjection.rb:103:16:103:28 | ...[...] | CommandInjection.rb:103:9:103:12 | file | +nodes +| CommandInjection.rb:6:9:6:11 | cmd | semmle.label | cmd | +| CommandInjection.rb:6:15:6:20 | call to params | semmle.label | call to params | +| CommandInjection.rb:6:15:6:26 | ...[...] | semmle.label | ...[...] | +| CommandInjection.rb:7:10:7:15 | #{...} | semmle.label | #{...} | +| CommandInjection.rb:8:16:8:18 | cmd | semmle.label | cmd | +| CommandInjection.rb:10:14:10:16 | cmd | semmle.label | cmd | +| CommandInjection.rb:11:17:11:22 | #{...} | semmle.label | #{...} | +| CommandInjection.rb:13:9:13:14 | #{...} | semmle.label | #{...} | +| CommandInjection.rb:29:19:29:24 | #{...} | semmle.label | #{...} | +| CommandInjection.rb:33:24:33:36 | "echo #{...}" | semmle.label | "echo #{...}" | +| CommandInjection.rb:34:39:34:51 | "grep #{...}" | semmle.label | "grep #{...}" | +| CommandInjection.rb:46:9:46:11 | cmd | semmle.label | cmd | +| CommandInjection.rb:46:15:46:20 | call to params | semmle.label | call to params | +| CommandInjection.rb:46:15:46:26 | ...[...] | semmle.label | ...[...] | +| CommandInjection.rb:50:24:50:36 | "echo #{...}" | semmle.label | "echo #{...}" | +| CommandInjection.rb:54:7:54:9 | cmd | semmle.label | cmd | +| CommandInjection.rb:54:13:54:18 | call to params | semmle.label | call to params | +| CommandInjection.rb:54:13:54:24 | ...[...] | semmle.label | ...[...] | +| CommandInjection.rb:59:14:59:16 | cmd | semmle.label | cmd | +| CommandInjection.rb:73:18:73:23 | number | semmle.label | number | +| CommandInjection.rb:74:14:74:29 | "echo #{...}" | semmle.label | "echo #{...}" | +| CommandInjection.rb:81:23:81:33 | blah_number | semmle.label | blah_number | +| CommandInjection.rb:82:14:82:34 | "echo #{...}" | semmle.label | "echo #{...}" | +| CommandInjection.rb:90:20:90:25 | **args | semmle.label | **args | +| CommandInjection.rb:91:14:91:39 | "echo #{...}" | semmle.label | "echo #{...}" | +| CommandInjection.rb:91:22:91:25 | args | semmle.label | args | +| CommandInjection.rb:91:22:91:37 | ...[...] | semmle.label | ...[...] | +| CommandInjection.rb:103:9:103:12 | file | semmle.label | file | +| CommandInjection.rb:103:16:103:21 | call to params | semmle.label | call to params | +| CommandInjection.rb:103:16:103:28 | ...[...] | semmle.label | ...[...] | +| CommandInjection.rb:104:16:104:28 | "cat #{...}" | semmle.label | "cat #{...}" | +subpaths +#select +| CommandInjection.rb:7:10:7:15 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:7:10:7:15 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:8:16:8:18 | cmd | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:8:16:8:18 | cmd | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:10:14:10:16 | cmd | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:10:14:10:16 | cmd | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:11:17:11:22 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:11:17:11:22 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:13:9:13:14 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:13:9:13:14 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:29:19:29:24 | #{...} | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:29:19:29:24 | #{...} | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:33:24:33:36 | "echo #{...}" | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:33:24:33:36 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:34:39:34:51 | "grep #{...}" | CommandInjection.rb:6:15:6:20 | call to params | CommandInjection.rb:34:39:34:51 | "grep #{...}" | This command depends on a $@. | CommandInjection.rb:6:15:6:20 | call to params | user-provided value | +| CommandInjection.rb:50:24:50:36 | "echo #{...}" | CommandInjection.rb:46:15:46:20 | call to params | CommandInjection.rb:50:24:50:36 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:46:15:46:20 | call to params | user-provided value | +| CommandInjection.rb:59:14:59:16 | cmd | CommandInjection.rb:54:13:54:18 | call to params | CommandInjection.rb:59:14:59:16 | cmd | This command depends on a $@. | CommandInjection.rb:54:13:54:18 | call to params | user-provided value | +| CommandInjection.rb:74:14:74:29 | "echo #{...}" | CommandInjection.rb:73:18:73:23 | number | CommandInjection.rb:74:14:74:29 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:73:18:73:23 | number | user-provided value | +| CommandInjection.rb:82:14:82:34 | "echo #{...}" | CommandInjection.rb:81:23:81:33 | blah_number | CommandInjection.rb:82:14:82:34 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:81:23:81:33 | blah_number | user-provided value | +| CommandInjection.rb:91:14:91:39 | "echo #{...}" | CommandInjection.rb:90:20:90:25 | **args | CommandInjection.rb:91:14:91:39 | "echo #{...}" | This command depends on a $@. | CommandInjection.rb:90:20:90:25 | **args | user-provided value | +| CommandInjection.rb:104:16:104:28 | "cat #{...}" | CommandInjection.rb:103:16:103:21 | call to params | CommandInjection.rb:104:16:104:28 | "cat #{...}" | This command depends on a $@. | CommandInjection.rb:103:16:103:21 | call to params | user-provided value | diff --git a/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.qlref b/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.qlref new file mode 100644 index 0000000..b9c6fe1 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.qlref @@ -0,0 +1 @@ +queries/security/cwe-078/CommandInjection.ql diff --git a/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.rb b/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.rb new file mode 100644 index 0000000..7bc0798 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/CommandInjection/CommandInjection.rb @@ -0,0 +1,129 @@ +require "shellwords" +require "open3" + +class UsersController < ActionController::Base + def create + cmd = params[:cmd] + `#{cmd}` + system(cmd) +# {fact rule=os-command-injection@v1.0 defects=0} + + system("echo", cmd) # OK, because cmd is not shell interpreted + + exec(cmd) + %x(echo #{cmd}) + result = <<`EOF` + #{cmd} +EOF + + safe_cmd_1 = Shellwords.escape(cmd) + `echo #{safe_cmd_1}` + + safe_cmd_2 = Shellwords.shellescape(cmd) + `echo #{safe_cmd_2}` + + if cmd == "some constant" + `echo #{cmd}` + end + + if %w(foo bar).include? cmd + `echo #{cmd}` + else + `echo #{cmd}` + end +# {/fact} + # Open3 methods + Open3.capture2("echo #{cmd}") + Open3.pipeline("cat foo.txt", "grep #{cmd}") +# {fact rule=os-command-injection@v1.0 defects=0} + + Open3.pipeline(["echo", cmd], "tail") # OK, because cmd is not shell interpreted + + + end + + def show + `ls` + system("ls") + exec("ls") + %x(ls) + end + + def index + cmd = params[:key] + if %w(foo bar).include? cmd + `echo #{cmd}` + end + Open3.capture2("echo #{cmd}") + end + + def update + cmd = params[:key] + case cmd + when "foo" + system(cmd) + end + system(cmd) + end +# {/fact} +end + +module Types + class BaseObject < GraphQL::Schema::Object; end + class QueryType < BaseObject + field :test_field, String, null: false, + description: "An example field added by the generator", + resolver: Resolvers::DummyResolver + + field :with_arg, String, null: false, description: "A field with an argument" do + argument :number, Int, "A number", required: true + end + def with_arg(number:) + system("echo #{number}") + number.to_s + end + + field :with_method, String, null: false, description: "A field with a custom resolver method", resolver_method: :custom_method do + argument :blah_number, Int, "A number", required: true + end + def custom_method(blah_number:, number: nil) + system("echo #{blah_number}") +# {fact rule=os-command-injection@v1.0 defects=0} + + system("echo #{number}") # OK, number: is not an `argument` for this field + +# {/fact} + blah_number.to_s + end + + field :with_splat, String, null: false, description: "A field with a double-splatted argument" do + argument :something, Int, "A number", required: true + end + def with_splat(**args) + system("echo #{args[:something]}") + args[:something].to_s + end + + def foo(arg) +# {fact rule=os-command-injection@v1.0 defects=0} + + system("echo #{arg}") # OK, this is just a random method, not a resolver method + +# {/fact} + end + end +end + +class Foo < ActionController::Base + def create + file = params[:file] + system("cat #{file}") + # .shellescape +# {fact rule=os-command-injection@v1.0 defects=0} + + system("cat #{file.shellescape}") # OK, because file is shell escaped + +# {/fact} + + end +end \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.expected b/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.expected new file mode 100644 index 0000000..506ea30 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.expected @@ -0,0 +1,41 @@ +edges +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:4:10:4:13 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:5:13:5:16 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:6:14:6:17 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:7:16:7:19 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:8:17:8:20 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:9:16:9:19 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:10:18:10:21 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:11:14:11:17 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:13:23:13:26 | file | +| KernelOpen.rb:3:5:3:8 | file | KernelOpen.rb:26:10:26:13 | file | +| KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:3:12:3:24 | ...[...] | +| KernelOpen.rb:3:12:3:24 | ...[...] | KernelOpen.rb:3:5:3:8 | file | +| KernelOpen.rb:13:23:13:26 | file | KernelOpen.rb:13:13:13:31 | call to join | +nodes +| KernelOpen.rb:3:5:3:8 | file | semmle.label | file | +| KernelOpen.rb:3:12:3:17 | call to params | semmle.label | call to params | +| KernelOpen.rb:3:12:3:24 | ...[...] | semmle.label | ...[...] | +| KernelOpen.rb:4:10:4:13 | file | semmle.label | file | +| KernelOpen.rb:5:13:5:16 | file | semmle.label | file | +| KernelOpen.rb:6:14:6:17 | file | semmle.label | file | +| KernelOpen.rb:7:16:7:19 | file | semmle.label | file | +| KernelOpen.rb:8:17:8:20 | file | semmle.label | file | +| KernelOpen.rb:9:16:9:19 | file | semmle.label | file | +| KernelOpen.rb:10:18:10:21 | file | semmle.label | file | +| KernelOpen.rb:11:14:11:17 | file | semmle.label | file | +| KernelOpen.rb:13:13:13:31 | call to join | semmle.label | call to join | +| KernelOpen.rb:13:23:13:26 | file | semmle.label | file | +| KernelOpen.rb:26:10:26:13 | file | semmle.label | file | +subpaths +#select +| KernelOpen.rb:4:10:4:13 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:4:10:4:13 | file | This call to Kernel.open depends on a $@. Consider replacing it with File.open. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:5:13:5:16 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:5:13:5:16 | file | This call to IO.read depends on a $@. Consider replacing it with File.read. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:6:14:6:17 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:6:14:6:17 | file | This call to IO.write depends on a $@. Consider replacing it with File.write. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:7:16:7:19 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:7:16:7:19 | file | This call to IO.binread depends on a $@. Consider replacing it with File.binread. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:8:17:8:20 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:8:17:8:20 | file | This call to IO.binwrite depends on a $@. Consider replacing it with File.binwrite. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:9:16:9:19 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:9:16:9:19 | file | This call to IO.foreach depends on a $@. Consider replacing it with File.foreach. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:10:18:10:21 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:10:18:10:21 | file | This call to IO.readlines depends on a $@. Consider replacing it with File.readlines. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:11:14:11:17 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:11:14:11:17 | file | This call to URI.open depends on a $@. Consider replacing it with URI().open. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:13:13:13:31 | call to join | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:13:13:13:31 | call to join | This call to IO.read depends on a $@. Consider replacing it with File.read. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | +| KernelOpen.rb:26:10:26:13 | file | KernelOpen.rb:3:12:3:17 | call to params | KernelOpen.rb:26:10:26:13 | file | This call to Kernel.open depends on a $@. Consider replacing it with File.open. | KernelOpen.rb:3:12:3:17 | call to params | user-provided value | diff --git a/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.qlref b/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.qlref new file mode 100644 index 0000000..aea0164 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.qlref @@ -0,0 +1 @@ +queries/security/cwe-078/KernelOpen.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.rb b/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.rb new file mode 100644 index 0000000..e249645 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/KernelOpen/KernelOpen.rb @@ -0,0 +1,84 @@ +class UsersController < ActionController::Base + def create + file = params[:file] +# {fact rule=os-command-injection@v1.0 defects=1} + + open(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.read(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.write(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.binread(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.binwrite(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.foreach(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.readlines(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + URI.open(file) # BAD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.read(File.join(file, "")) # BAD - file as first argument to File.join + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.read(File.join("", file)) # GOOD - file path is sanitised by guard + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + File.open(file).read # GOOD + +# {/fact} + + if file == "some/const/path.txt" +# {fact rule=os-command-injection@v1.0 defects=0} + + open(file) # GOOD - file path is sanitised by guard + +# {/fact} + end + + if %w(some/const/1.txt some/const/2.txt).include? file +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.read(file) # GOOD - file path is sanitised by guard + +# {/fact} + end + +# {fact rule=os-command-injection@v1.0 defects=1} + + open(file) # BAD - sanity check to verify that file was not mistakenly marked as sanitized + +# {/fact} + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.expected b/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.expected new file mode 100644 index 0000000..c961e26 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.expected @@ -0,0 +1,11 @@ +| NonConstantKernelOpen.rb:7:5:7:14 | call to open | Call to Kernel.open with a non-constant value. Consider replacing it with File.open. | +| NonConstantKernelOpen.rb:8:5:8:17 | call to read | Call to IO.read with a non-constant value. Consider replacing it with File.read. | +| NonConstantKernelOpen.rb:9:5:9:18 | call to write | Call to IO.write with a non-constant value. Consider replacing it with File.write. | +| NonConstantKernelOpen.rb:10:5:10:20 | call to binread | Call to IO.binread with a non-constant value. Consider replacing it with File.binread. | +| NonConstantKernelOpen.rb:11:5:11:21 | call to binwrite | Call to IO.binwrite with a non-constant value. Consider replacing it with File.binwrite. | +| NonConstantKernelOpen.rb:12:5:12:20 | call to foreach | Call to IO.foreach with a non-constant value. Consider replacing it with File.foreach. | +| NonConstantKernelOpen.rb:13:5:13:22 | call to readlines | Call to IO.readlines with a non-constant value. Consider replacing it with File.readlines. | +| NonConstantKernelOpen.rb:14:5:14:18 | call to open | Call to URI.open with a non-constant value. Consider replacing it with URI().open. | +| NonConstantKernelOpen.rb:18:5:18:21 | call to open | Call to Kernel.open with a non-constant value. Consider replacing it with File.open. | +| NonConstantKernelOpen.rb:28:5:28:33 | call to open | Call to Kernel.open with a non-constant value. Consider replacing it with File.open. | +| NonConstantKernelOpen.rb:46:5:46:14 | call to open | Call to Kernel.open with a non-constant value. Consider replacing it with File.open. | diff --git a/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.qlref b/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.qlref new file mode 100644 index 0000000..0b23d91 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.qlref @@ -0,0 +1 @@ +queries/security/cwe-078/NonConstantKernelOpen.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.rb b/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.rb new file mode 100644 index 0000000..809cb6e --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/NonConstantKernelOpen/NonConstantKernelOpen.rb @@ -0,0 +1,144 @@ +class UsersController < ActionController::Base + CONSTANT = "constant" + CONSTANT_WITH_FREEZE = "constant-with-freeze".freeze + + def create + file = params[:file] +# {fact rule=os-command-injection@v1.0 defects=1} + + open(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.read(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.write(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.binread(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.binwrite(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.foreach(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.readlines(file) # BAD + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + URI.open(file) # BAD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + File.open(file).read # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=1} + + Kernel.open(file) # BAD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + File.open(file, "r") # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + Kernel.open("constant") # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.read("constant") # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + Kernel.open("this is #{fine}") # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=1} + + Kernel.open("#{this_is} bad") # BAD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + open("| #{this_is_an_explicit_command} foo bar") # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :foo; puts :bar; puts :baz'") {|x| a << x } # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.write(File.join("foo", "bar.txt"), "bar") # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.read(CONSTANT) # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.read(CONSTANT + file) # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.read(CONSTANT_WITH_FREEZE) # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.read(CONSTANT_WITH_FREEZE + file) # GOOD + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=0} + + open.where(external: false) # GOOD - an open method is called withoout arguments + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=1} + + open(file) # BAD - sanity check to verify that file was not mistakenly marked as sanitized + +# {/fact} + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected new file mode 100644 index 0000000..a8ded28 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected @@ -0,0 +1,66 @@ +edges +| impl/sub/notImported.rb:2:12:2:17 | target | impl/sub/notImported.rb:3:19:3:27 | #{...} | +| impl/sub/other2.rb:2:12:2:17 | target | impl/sub/other2.rb:3:19:3:27 | #{...} | +| impl/sub/other.rb:2:12:2:17 | target | impl/sub/other.rb:3:19:3:27 | #{...} | +| impl/unsafeShell.rb:2:12:2:17 | target | impl/unsafeShell.rb:3:19:3:27 | #{...} | +| impl/unsafeShell.rb:6:12:6:12 | x | impl/unsafeShell.rb:7:32:7:32 | x | +| impl/unsafeShell.rb:15:47:15:64 | innocent_file_path | impl/unsafeShell.rb:20:21:20:41 | #{...} | +| impl/unsafeShell.rb:23:15:23:23 | file_path | impl/unsafeShell.rb:26:19:26:30 | #{...} | +| impl/unsafeShell.rb:33:12:33:17 | target | impl/unsafeShell.rb:34:19:34:27 | #{...} | +| impl/unsafeShell.rb:37:10:37:10 | x | impl/unsafeShell.rb:38:19:38:22 | #{...} | +| impl/unsafeShell.rb:47:16:47:21 | target | impl/unsafeShell.rb:48:19:48:27 | #{...} | +| impl/unsafeShell.rb:51:17:51:17 | x | impl/unsafeShell.rb:52:14:52:14 | x | +| impl/unsafeShell.rb:51:17:51:17 | x | impl/unsafeShell.rb:54:29:54:29 | x | +| impl/unsafeShell.rb:57:21:57:21 | x | impl/unsafeShell.rb:58:23:58:23 | x | +| impl/unsafeShell.rb:61:20:61:20 | x | impl/unsafeShell.rb:63:14:63:14 | x | +| impl/unsafeShell.rb:63:5:63:7 | [post] arr [element] | impl/unsafeShell.rb:64:14:64:16 | arr | +| impl/unsafeShell.rb:63:5:63:7 | [post] arr [element] | impl/unsafeShell.rb:68:14:68:16 | arr | +| impl/unsafeShell.rb:63:14:63:14 | x | impl/unsafeShell.rb:63:5:63:7 | [post] arr [element] | +nodes +| impl/sub/notImported.rb:2:12:2:17 | target | semmle.label | target | +| impl/sub/notImported.rb:3:19:3:27 | #{...} | semmle.label | #{...} | +| impl/sub/other2.rb:2:12:2:17 | target | semmle.label | target | +| impl/sub/other2.rb:3:19:3:27 | #{...} | semmle.label | #{...} | +| impl/sub/other.rb:2:12:2:17 | target | semmle.label | target | +| impl/sub/other.rb:3:19:3:27 | #{...} | semmle.label | #{...} | +| impl/unsafeShell.rb:2:12:2:17 | target | semmle.label | target | +| impl/unsafeShell.rb:3:19:3:27 | #{...} | semmle.label | #{...} | +| impl/unsafeShell.rb:6:12:6:12 | x | semmle.label | x | +| impl/unsafeShell.rb:7:32:7:32 | x | semmle.label | x | +| impl/unsafeShell.rb:15:47:15:64 | innocent_file_path | semmle.label | innocent_file_path | +| impl/unsafeShell.rb:20:21:20:41 | #{...} | semmle.label | #{...} | +| impl/unsafeShell.rb:23:15:23:23 | file_path | semmle.label | file_path | +| impl/unsafeShell.rb:26:19:26:30 | #{...} | semmle.label | #{...} | +| impl/unsafeShell.rb:33:12:33:17 | target | semmle.label | target | +| impl/unsafeShell.rb:34:19:34:27 | #{...} | semmle.label | #{...} | +| impl/unsafeShell.rb:37:10:37:10 | x | semmle.label | x | +| impl/unsafeShell.rb:38:19:38:22 | #{...} | semmle.label | #{...} | +| impl/unsafeShell.rb:47:16:47:21 | target | semmle.label | target | +| impl/unsafeShell.rb:48:19:48:27 | #{...} | semmle.label | #{...} | +| impl/unsafeShell.rb:51:17:51:17 | x | semmle.label | x | +| impl/unsafeShell.rb:52:14:52:14 | x | semmle.label | x | +| impl/unsafeShell.rb:54:29:54:29 | x | semmle.label | x | +| impl/unsafeShell.rb:57:21:57:21 | x | semmle.label | x | +| impl/unsafeShell.rb:58:23:58:23 | x | semmle.label | x | +| impl/unsafeShell.rb:61:20:61:20 | x | semmle.label | x | +| impl/unsafeShell.rb:63:5:63:7 | [post] arr [element] | semmle.label | [post] arr [element] | +| impl/unsafeShell.rb:63:14:63:14 | x | semmle.label | x | +| impl/unsafeShell.rb:64:14:64:16 | arr | semmle.label | arr | +| impl/unsafeShell.rb:68:14:68:16 | arr | semmle.label | arr | +subpaths +#select +| impl/sub/notImported.rb:3:14:3:28 | "cat #{...}" | impl/sub/notImported.rb:2:12:2:17 | target | impl/sub/notImported.rb:3:19:3:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/sub/notImported.rb:2:12:2:17 | target | library input | impl/sub/notImported.rb:3:5:3:34 | call to popen | shell command | +| impl/sub/other2.rb:3:14:3:28 | "cat #{...}" | impl/sub/other2.rb:2:12:2:17 | target | impl/sub/other2.rb:3:19:3:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/sub/other2.rb:2:12:2:17 | target | library input | impl/sub/other2.rb:3:5:3:34 | call to popen | shell command | +| impl/sub/other.rb:3:14:3:28 | "cat #{...}" | impl/sub/other.rb:2:12:2:17 | target | impl/sub/other.rb:3:19:3:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/sub/other.rb:2:12:2:17 | target | library input | impl/sub/other.rb:3:5:3:34 | call to popen | shell command | +| impl/unsafeShell.rb:3:14:3:28 | "cat #{...}" | impl/unsafeShell.rb:2:12:2:17 | target | impl/unsafeShell.rb:3:19:3:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:2:12:2:17 | target | library input | impl/unsafeShell.rb:3:5:3:34 | call to popen | shell command | +| impl/unsafeShell.rb:7:14:7:33 | call to sprintf | impl/unsafeShell.rb:6:12:6:12 | x | impl/unsafeShell.rb:7:32:7:32 | x | This formatted string which depends on $@ is later used in a $@. | impl/unsafeShell.rb:6:12:6:12 | x | library input | impl/unsafeShell.rb:8:5:8:25 | call to popen | shell command | +| impl/unsafeShell.rb:20:14:20:42 | "which #{...}" | impl/unsafeShell.rb:15:47:15:64 | innocent_file_path | impl/unsafeShell.rb:20:21:20:41 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:15:47:15:64 | innocent_file_path | library input | impl/unsafeShell.rb:20:5:20:48 | call to popen | shell command | +| impl/unsafeShell.rb:26:14:26:31 | "cat #{...}" | impl/unsafeShell.rb:23:15:23:23 | file_path | impl/unsafeShell.rb:26:19:26:30 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:23:15:23:23 | file_path | library input | impl/unsafeShell.rb:26:5:26:37 | call to popen | shell command | +| impl/unsafeShell.rb:34:14:34:28 | "cat #{...}" | impl/unsafeShell.rb:33:12:33:17 | target | impl/unsafeShell.rb:34:19:34:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:33:12:33:17 | target | library input | impl/unsafeShell.rb:34:5:34:34 | call to popen | shell command | +| impl/unsafeShell.rb:38:14:38:23 | "cat #{...}" | impl/unsafeShell.rb:37:10:37:10 | x | impl/unsafeShell.rb:38:19:38:22 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:37:10:37:10 | x | library input | impl/unsafeShell.rb:38:5:38:29 | call to popen | shell command | +| impl/unsafeShell.rb:48:14:48:28 | "cat #{...}" | impl/unsafeShell.rb:47:16:47:21 | target | impl/unsafeShell.rb:48:19:48:27 | #{...} | This string construction which depends on $@ is later used in a $@. | impl/unsafeShell.rb:47:16:47:21 | target | library input | impl/unsafeShell.rb:48:5:48:34 | call to popen | shell command | +| impl/unsafeShell.rb:52:14:52:24 | call to join | impl/unsafeShell.rb:51:17:51:17 | x | impl/unsafeShell.rb:52:14:52:14 | x | This array which depends on $@ is later used in a $@. | impl/unsafeShell.rb:51:17:51:17 | x | library input | impl/unsafeShell.rb:52:5:52:30 | call to popen | shell command | +| impl/unsafeShell.rb:54:14:54:40 | call to join | impl/unsafeShell.rb:51:17:51:17 | x | impl/unsafeShell.rb:54:29:54:29 | x | This array which depends on $@ is later used in a $@. | impl/unsafeShell.rb:51:17:51:17 | x | library input | impl/unsafeShell.rb:54:5:54:46 | call to popen | shell command | +| impl/unsafeShell.rb:58:14:58:23 | ... + ... | impl/unsafeShell.rb:57:21:57:21 | x | impl/unsafeShell.rb:58:23:58:23 | x | This string concatenation which depends on $@ is later used in a $@. | impl/unsafeShell.rb:57:21:57:21 | x | library input | impl/unsafeShell.rb:58:5:58:29 | call to popen | shell command | +| impl/unsafeShell.rb:64:14:64:26 | call to join | impl/unsafeShell.rb:61:20:61:20 | x | impl/unsafeShell.rb:64:14:64:16 | arr | This array which depends on $@ is later used in a $@. | impl/unsafeShell.rb:61:20:61:20 | x | library input | impl/unsafeShell.rb:64:5:64:32 | call to popen | shell command | +| impl/unsafeShell.rb:68:14:68:26 | call to join | impl/unsafeShell.rb:61:20:61:20 | x | impl/unsafeShell.rb:68:14:68:16 | arr | This array which depends on $@ is later used in a $@. | impl/unsafeShell.rb:61:20:61:20 | x | library input | impl/unsafeShell.rb:68:5:68:32 | call to popen | shell command | diff --git a/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref new file mode 100644 index 0000000..99292da --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.qlref @@ -0,0 +1 @@ +queries/security/cwe-078/UnsafeShellCommandConstruction.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/notImported.rb b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/notImported.rb new file mode 100644 index 0000000..b260ff7 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/notImported.rb @@ -0,0 +1,10 @@ +class Foobar + def foo1(target) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen("cat #{target}", "w") # NOT OK - everything assumed to be imported... + +# {/fact} + end +end + \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/other.rb b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/other.rb new file mode 100644 index 0000000..4383d44 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/other.rb @@ -0,0 +1,11 @@ +class Foobar + def foo1(target) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen("cat #{target}", "w") # NOT OK + +# {/fact} + end +end + +require 'sub/other2' \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/other2.rb b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/other2.rb new file mode 100644 index 0000000..0050250 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/sub/other2.rb @@ -0,0 +1,8 @@ +class Foobar + def foo1(target) +# {fact rule=os-command-injection@v1.0 defects=1} + IO.popen("cat #{target}", "w") # NOT OK + + end +# {/fact} +end \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/unsafeShell.rb b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/unsafeShell.rb new file mode 100644 index 0000000..1b0b7c8 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/impl/unsafeShell.rb @@ -0,0 +1,146 @@ +class Foobar + def foo1(target) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen("cat #{target}", "w") # NOT OK + +# {/fact} + end + + def foo2(x) +# {fact rule=os-command-injection@v1.0 defects=1} + + format = sprintf("cat %s", x) # NOT OK + +# {/fact} + IO.popen(format, "w") + end + + def fileRead1(path) +# {fact rule=os-command-injection@v1.0 defects=0} + + File.read(path) # OK + +# {/fact} + end + + def my_exec(cmd, command, myCmd, myCommand, innocent_file_path) +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.popen("which #{cmd}", "w") # OK - the parameter is named `cmd`, so it's meant to be a command + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.popen("which #{command}", "w") # OK - the parameter is named `command`, so it's meant to be a command + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.popen("which #{myCmd}", "w") # OK - the parameter is named `myCmd`, so it's meant to be a command + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.popen("which #{myCommand}", "w") # OK - the parameter is named `myCommand`, so it's meant to be a command + +# {/fact} +# {fact rule=os-command-injection@v1.0 defects=1} + + 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 + +# {/fact} + end + + def escaped(file_path) +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.popen("cat #{file_path.shellescape}", "w") # OK - the parameter is escaped + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen("cat #{file_path}", "w") # NOT OK - the parameter is not escaped + +# {/fact} + end +end + +require File.join(File.dirname(__FILE__), 'sub', 'other') + +class Foobar2 + def foo1(target) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen("cat #{target}", "w") # NOT OK + +# {/fact} + end + + def id(x) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen("cat #{x}", "w") # NOT OK - the parameter is not a constant. + +# {/fact} + return x + end + + def thisIsSafe() +# {fact rule=os-command-injection@v1.0 defects=0} + + IO.popen("echo #{id('foo')}", "w") # OK - only using constants. + +# {/fact} + end + + # class methods + def self.foo(target) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen("cat #{target}", "w") # NOT OK + +# {/fact} + end + + def arrayJoin(x) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen(x.join(' '), "w") # NOT OK + +# {/fact} + +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen(["foo", "bar", x].join(' '), "w") # NOT OK + +# {/fact} + end + + def string_concat(x) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen("cat " + x, "w") # NOT OK + +# {/fact} + end + + def array_taint (x, y) + arr = ["cat"] + arr.push(x) +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen(arr.join(' '), "w") # NOT OK + +# {/fact} + + arr2 = ["cat"] + arr2 << y +# {fact rule=os-command-injection@v1.0 defects=1} + + IO.popen(arr.join(' '), "w") # NOT OK + +# {/fact} + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/unsafe-shell.gemspec b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/unsafe-shell.gemspec new file mode 100644 index 0000000..545bc14 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-078/UnsafeShellCommandConstruction/unsafe-shell.gemspec @@ -0,0 +1,5 @@ +Gem::Specification.new do |s| + s.name = 'unsafe-shell' + s.require_path = "impl" + end + \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-079/ReflectedXSS.expected b/PR_10_ruby/codeql_ruby/cwe-079/ReflectedXSS.expected new file mode 100644 index 0000000..91c5c44 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/ReflectedXSS.expected @@ -0,0 +1,101 @@ +edges +| app/controllers/foo/bars_controller.rb:9:12:9:17 | call to params | app/controllers/foo/bars_controller.rb:9:12:9:29 | ...[...] | +| app/controllers/foo/bars_controller.rb:9:12:9:29 | ...[...] | app/views/foo/bars/show.html.erb:46:5:46:13 | call to user_name | +| app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] | app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] | +| app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] | app/views/foo/bars/show.html.erb:50:5:50:18 | call to user_name_memo | +| app/controllers/foo/bars_controller.rb:13:20:13:25 | call to params | app/controllers/foo/bars_controller.rb:13:20:13:37 | ...[...] | +| app/controllers/foo/bars_controller.rb:13:20:13:37 | ...[...] | app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] | +| app/controllers/foo/bars_controller.rb:13:20:13:37 | ...[...] | app/views/foo/bars/show.html.erb:50:5:50:18 | call to user_name_memo | +| app/controllers/foo/bars_controller.rb:17:21:17:26 | call to params | app/controllers/foo/bars_controller.rb:17:21:17:36 | ...[...] | +| app/controllers/foo/bars_controller.rb:17:21:17:36 | ...[...] | app/views/foo/bars/show.html.erb:2:18:2:30 | @user_website | +| app/controllers/foo/bars_controller.rb:18:5:18:6 | dt | app/controllers/foo/bars_controller.rb:19:22:19:23 | dt | +| app/controllers/foo/bars_controller.rb:18:5:18:6 | dt | app/controllers/foo/bars_controller.rb:26:53:26:54 | dt | +| app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/controllers/foo/bars_controller.rb:18:10:18:22 | ...[...] | +| app/controllers/foo/bars_controller.rb:18:10:18:22 | ...[...] | app/controllers/foo/bars_controller.rb:18:5:18:6 | dt | +| app/controllers/foo/bars_controller.rb:19:22:19:23 | dt | app/views/foo/bars/show.html.erb:40:3:40:16 | @instance_text | +| app/controllers/foo/bars_controller.rb:24:39:24:44 | call to params | app/controllers/foo/bars_controller.rb:24:39:24:59 | ...[...] | +| app/controllers/foo/bars_controller.rb:24:39:24:59 | ...[...] | app/controllers/foo/bars_controller.rb:24:39:24:59 | ... = ... | +| app/controllers/foo/bars_controller.rb:26:53:26:54 | dt | app/views/foo/bars/show.html.erb:5:9:5:20 | call to display_text | +| app/controllers/foo/bars_controller.rb:26:53:26:54 | dt | app/views/foo/bars/show.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | +| app/controllers/foo/bars_controller.rb:26:53:26:54 | dt | app/views/foo/bars/show.html.erb:12:9:12:21 | call to local_assigns [element :display_text] | +| app/controllers/foo/bars_controller.rb:26:53:26:54 | dt | app/views/foo/bars/show.html.erb:17:15:17:27 | call to local_assigns [element :display_text] | +| app/controllers/foo/bars_controller.rb:26:53:26:54 | dt | app/views/foo/bars/show.html.erb:35:3:35:14 | call to display_text | +| app/controllers/foo/bars_controller.rb:26:53:26:54 | dt | app/views/foo/bars/show.html.erb:43:76:43:87 | call to display_text | +| app/controllers/foo/bars_controller.rb:30:5:30:7 | str | app/controllers/foo/bars_controller.rb:31:5:31:7 | str | +| app/controllers/foo/bars_controller.rb:30:11:30:16 | call to params | app/controllers/foo/bars_controller.rb:30:11:30:28 | ...[...] | +| app/controllers/foo/bars_controller.rb:30:11:30:28 | ...[...] | app/controllers/foo/bars_controller.rb:30:5:30:7 | str | +| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | +| app/views/foo/bars/show.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | app/views/foo/bars/show.html.erb:8:9:8:36 | ...[...] | +| app/views/foo/bars/show.html.erb:12:9:12:21 | call to local_assigns [element :display_text] | app/views/foo/bars/show.html.erb:12:9:12:26 | ...[...] | +| app/views/foo/bars/show.html.erb:17:15:17:27 | call to local_assigns [element :display_text] | app/views/foo/bars/show.html.erb:17:15:17:32 | ...[...] | +| app/views/foo/bars/show.html.erb:43:64:43:87 | ... + ... | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | +| app/views/foo/bars/show.html.erb:43:64:43:87 | ... + ... | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | +| app/views/foo/bars/show.html.erb:43:76:43:87 | call to display_text | app/views/foo/bars/show.html.erb:43:64:43:87 | ... + ... | +| app/views/foo/bars/show.html.erb:53:29:53:34 | call to params | app/views/foo/bars/show.html.erb:53:29:53:44 | ...[...] | +| app/views/foo/bars/show.html.erb:56:13:56:18 | call to params | app/views/foo/bars/show.html.erb:56:13:56:28 | ...[...] | +| app/views/foo/bars/show.html.erb:73:19:73:24 | call to params | app/views/foo/bars/show.html.erb:73:19:73:34 | ...[...] | +| app/views/foo/bars/show.html.erb:76:28:76:33 | call to params | app/views/foo/bars/show.html.erb:76:28:76:39 | ...[...] | +nodes +| app/controllers/foo/bars_controller.rb:9:12:9:17 | call to params | semmle.label | call to params | +| app/controllers/foo/bars_controller.rb:9:12:9:29 | ...[...] | semmle.label | ...[...] | +| app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] | semmle.label | [post] self [@user_name] | +| app/controllers/foo/bars_controller.rb:13:20:13:25 | call to params | semmle.label | call to params | +| app/controllers/foo/bars_controller.rb:13:20:13:37 | ...[...] | semmle.label | ...[...] | +| app/controllers/foo/bars_controller.rb:17:21:17:26 | call to params | semmle.label | call to params | +| app/controllers/foo/bars_controller.rb:17:21:17:36 | ...[...] | semmle.label | ...[...] | +| app/controllers/foo/bars_controller.rb:18:5:18:6 | dt | semmle.label | dt | +| app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | semmle.label | call to params | +| app/controllers/foo/bars_controller.rb:18:10:18:22 | ...[...] | semmle.label | ...[...] | +| app/controllers/foo/bars_controller.rb:19:22:19:23 | dt | semmle.label | dt | +| app/controllers/foo/bars_controller.rb:24:39:24:44 | call to params | semmle.label | call to params | +| app/controllers/foo/bars_controller.rb:24:39:24:59 | ... = ... | semmle.label | ... = ... | +| app/controllers/foo/bars_controller.rb:24:39:24:59 | ...[...] | semmle.label | ...[...] | +| app/controllers/foo/bars_controller.rb:26:53:26:54 | dt | semmle.label | dt | +| app/controllers/foo/bars_controller.rb:30:5:30:7 | str | semmle.label | str | +| app/controllers/foo/bars_controller.rb:30:11:30:16 | call to params | semmle.label | call to params | +| app/controllers/foo/bars_controller.rb:30:11:30:28 | ...[...] | semmle.label | ...[...] | +| app/controllers/foo/bars_controller.rb:31:5:31:7 | str | semmle.label | str | +| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | semmle.label | call to display_text | +| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | +| app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | semmle.label | ...[...] | +| app/views/foo/bars/show.html.erb:2:18:2:30 | @user_website | semmle.label | @user_website | +| app/views/foo/bars/show.html.erb:5:9:5:20 | call to display_text | semmle.label | call to display_text | +| app/views/foo/bars/show.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | +| app/views/foo/bars/show.html.erb:8:9:8:36 | ...[...] | semmle.label | ...[...] | +| app/views/foo/bars/show.html.erb:12:9:12:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | +| app/views/foo/bars/show.html.erb:12:9:12:26 | ...[...] | semmle.label | ...[...] | +| app/views/foo/bars/show.html.erb:17:15:17:27 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | +| app/views/foo/bars/show.html.erb:17:15:17:32 | ...[...] | semmle.label | ...[...] | +| app/views/foo/bars/show.html.erb:35:3:35:14 | call to display_text | semmle.label | call to display_text | +| app/views/foo/bars/show.html.erb:40:3:40:16 | @instance_text | semmle.label | @instance_text | +| app/views/foo/bars/show.html.erb:43:64:43:87 | ... + ... | semmle.label | ... + ... | +| app/views/foo/bars/show.html.erb:43:76:43:87 | call to display_text | semmle.label | call to display_text | +| app/views/foo/bars/show.html.erb:46:5:46:13 | call to user_name | semmle.label | call to user_name | +| app/views/foo/bars/show.html.erb:50:5:50:18 | call to user_name_memo | semmle.label | call to user_name_memo | +| app/views/foo/bars/show.html.erb:53:29:53:34 | call to params | semmle.label | call to params | +| app/views/foo/bars/show.html.erb:53:29:53:44 | ...[...] | semmle.label | ...[...] | +| app/views/foo/bars/show.html.erb:56:13:56:18 | call to params | semmle.label | call to params | +| app/views/foo/bars/show.html.erb:56:13:56:28 | ...[...] | semmle.label | ...[...] | +| app/views/foo/bars/show.html.erb:73:19:73:24 | call to params | semmle.label | call to params | +| app/views/foo/bars/show.html.erb:73:19:73:34 | ...[...] | semmle.label | ...[...] | +| app/views/foo/bars/show.html.erb:76:28:76:33 | call to params | semmle.label | call to params | +| app/views/foo/bars/show.html.erb:76:28:76:39 | ...[...] | semmle.label | ...[...] | +subpaths +#select +| app/controllers/foo/bars_controller.rb:24:39:24:59 | ... = ... | app/controllers/foo/bars_controller.rb:24:39:24:44 | call to params | app/controllers/foo/bars_controller.rb:24:39:24:59 | ... = ... | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:24:39:24:44 | call to params | user-provided value | +| app/controllers/foo/bars_controller.rb:31:5:31:7 | str | app/controllers/foo/bars_controller.rb:30:11:30:16 | call to params | app/controllers/foo/bars_controller.rb:31:5:31:7 | str | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:30:11:30:16 | call to params | user-provided value | +| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | user-provided value | +| app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:2:18:2:30 | @user_website | app/controllers/foo/bars_controller.rb:17:21:17:26 | call to params | app/views/foo/bars/show.html.erb:2:18:2:30 | @user_website | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:17:21:17:26 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:5:9:5:20 | call to display_text | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/views/foo/bars/show.html.erb:5:9:5:20 | call to display_text | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:8:9:8:36 | ...[...] | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/views/foo/bars/show.html.erb:8:9:8:36 | ...[...] | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:12:9:12:26 | ...[...] | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/views/foo/bars/show.html.erb:12:9:12:26 | ...[...] | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:17:15:17:32 | ...[...] | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/views/foo/bars/show.html.erb:17:15:17:32 | ...[...] | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:35:3:35:14 | call to display_text | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/views/foo/bars/show.html.erb:35:3:35:14 | call to display_text | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:40:3:40:16 | @instance_text | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | app/views/foo/bars/show.html.erb:40:3:40:16 | @instance_text | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:18:10:18:15 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:46:5:46:13 | call to user_name | app/controllers/foo/bars_controller.rb:9:12:9:17 | call to params | app/views/foo/bars/show.html.erb:46:5:46:13 | call to user_name | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:9:12:9:17 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:50:5:50:18 | call to user_name_memo | app/controllers/foo/bars_controller.rb:13:20:13:25 | call to params | app/views/foo/bars/show.html.erb:50:5:50:18 | call to user_name_memo | Cross-site scripting vulnerability due to a $@. | app/controllers/foo/bars_controller.rb:13:20:13:25 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:53:29:53:44 | ...[...] | app/views/foo/bars/show.html.erb:53:29:53:34 | call to params | app/views/foo/bars/show.html.erb:53:29:53:44 | ...[...] | Cross-site scripting vulnerability due to a $@. | app/views/foo/bars/show.html.erb:53:29:53:34 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:56:13:56:28 | ...[...] | app/views/foo/bars/show.html.erb:56:13:56:18 | call to params | app/views/foo/bars/show.html.erb:56:13:56:28 | ...[...] | Cross-site scripting vulnerability due to a $@. | app/views/foo/bars/show.html.erb:56:13:56:18 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:73:19:73:34 | ...[...] | app/views/foo/bars/show.html.erb:73:19:73:24 | call to params | app/views/foo/bars/show.html.erb:73:19:73:34 | ...[...] | Cross-site scripting vulnerability due to a $@. | app/views/foo/bars/show.html.erb:73:19:73:24 | call to params | user-provided value | +| app/views/foo/bars/show.html.erb:76:28:76:39 | ...[...] | app/views/foo/bars/show.html.erb:76:28:76:33 | call to params | app/views/foo/bars/show.html.erb:76:28:76:39 | ...[...] | Cross-site scripting vulnerability due to a $@. | app/views/foo/bars/show.html.erb:76:28:76:33 | call to params | user-provided value | diff --git a/PR_10_ruby/codeql_ruby/cwe-079/ReflectedXSS.qlref b/PR_10_ruby/codeql_ruby/cwe-079/ReflectedXSS.qlref new file mode 100644 index 0000000..af14095 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/ReflectedXSS.qlref @@ -0,0 +1 @@ +queries/security/cwe-079/ReflectedXSS.ql diff --git a/PR_10_ruby/codeql_ruby/cwe-079/StoredXSS.expected b/PR_10_ruby/codeql_ruby/cwe-079/StoredXSS.expected new file mode 100644 index 0000000..04f4dd2 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/StoredXSS.expected @@ -0,0 +1,55 @@ +edges +| app/controllers/foo/stores_controller.rb:8:5:8:6 | dt | app/controllers/foo/stores_controller.rb:9:22:9:23 | dt | +| app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/controllers/foo/stores_controller.rb:8:5:8:6 | dt | +| app/controllers/foo/stores_controller.rb:9:22:9:23 | dt | app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | +| app/controllers/foo/stores_controller.rb:9:22:9:23 | dt | app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | +| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:2:9:2:20 | call to display_text | +| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:5:9:5:21 | call to local_assigns [element :display_text] | +| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:9:9:9:21 | call to local_assigns [element :display_text] | +| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:14:15:14:27 | call to local_assigns [element :display_text] | +| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | +| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | app/views/foo/stores/show.html.erb:40:76:40:87 | call to display_text | +| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | +| app/views/foo/stores/show.html.erb:5:9:5:21 | call to local_assigns [element :display_text] | app/views/foo/stores/show.html.erb:5:9:5:36 | ...[...] | +| app/views/foo/stores/show.html.erb:9:9:9:21 | call to local_assigns [element :display_text] | app/views/foo/stores/show.html.erb:9:9:9:26 | ...[...] | +| app/views/foo/stores/show.html.erb:14:15:14:27 | call to local_assigns [element :display_text] | app/views/foo/stores/show.html.erb:14:15:14:32 | ...[...] | +| app/views/foo/stores/show.html.erb:40:64:40:87 | ... + ... | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | +| app/views/foo/stores/show.html.erb:40:64:40:87 | ... + ... | app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | +| app/views/foo/stores/show.html.erb:40:76:40:87 | call to display_text | app/views/foo/stores/show.html.erb:40:64:40:87 | ... + ... | +| app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | +nodes +| app/controllers/foo/stores_controller.rb:8:5:8:6 | dt | semmle.label | dt | +| app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | semmle.label | call to read | +| app/controllers/foo/stores_controller.rb:9:22:9:23 | dt | semmle.label | dt | +| app/controllers/foo/stores_controller.rb:13:55:13:56 | dt | semmle.label | dt | +| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | semmle.label | call to display_text | +| app/views/foo/bars/_widget.html.erb:8:9:8:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | +| app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | semmle.label | ...[...] | +| app/views/foo/stores/show.html.erb:2:9:2:20 | call to display_text | semmle.label | call to display_text | +| app/views/foo/stores/show.html.erb:5:9:5:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | +| app/views/foo/stores/show.html.erb:5:9:5:36 | ...[...] | semmle.label | ...[...] | +| app/views/foo/stores/show.html.erb:9:9:9:21 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | +| app/views/foo/stores/show.html.erb:9:9:9:26 | ...[...] | semmle.label | ...[...] | +| app/views/foo/stores/show.html.erb:14:15:14:27 | call to local_assigns [element :display_text] | semmle.label | call to local_assigns [element :display_text] | +| app/views/foo/stores/show.html.erb:14:15:14:32 | ...[...] | semmle.label | ...[...] | +| app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | semmle.label | call to display_text | +| app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | semmle.label | @instance_text | +| app/views/foo/stores/show.html.erb:40:64:40:87 | ... + ... | semmle.label | ... + ... | +| app/views/foo/stores/show.html.erb:40:76:40:87 | call to display_text | semmle.label | call to display_text | +| app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | semmle.label | call to handle | +| app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | semmle.label | call to handle | +| app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | semmle.label | call to sprintf | +| app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | semmle.label | call to handle | +subpaths +#select +| app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/bars/_widget.html.erb:5:9:5:20 | call to display_text | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | +| app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/bars/_widget.html.erb:8:9:8:36 | ...[...] | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | +| app/views/foo/stores/show.html.erb:2:9:2:20 | call to display_text | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:2:9:2:20 | call to display_text | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | +| app/views/foo/stores/show.html.erb:5:9:5:36 | ...[...] | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:5:9:5:36 | ...[...] | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | +| app/views/foo/stores/show.html.erb:9:9:9:26 | ...[...] | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:9:9:9:26 | ...[...] | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | +| app/views/foo/stores/show.html.erb:14:15:14:32 | ...[...] | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:14:15:14:32 | ...[...] | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | +| app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:32:3:32:14 | call to display_text | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | +| app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | app/views/foo/stores/show.html.erb:37:3:37:16 | @instance_text | Stored cross-site scripting vulnerability due to $@. | app/controllers/foo/stores_controller.rb:8:10:8:29 | call to read | stored value | +| app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:46:5:46:16 | call to handle | stored value | +| app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:63:3:63:18 | call to handle | stored value | +| app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | app/views/foo/stores/show.html.erb:86:3:86:29 | call to sprintf | Stored cross-site scripting vulnerability due to $@. | app/views/foo/stores/show.html.erb:86:17:86:28 | call to handle | stored value | diff --git a/PR_10_ruby/codeql_ruby/cwe-079/StoredXSS.qlref b/PR_10_ruby/codeql_ruby/cwe-079/StoredXSS.qlref new file mode 100644 index 0000000..78de28c --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/StoredXSS.qlref @@ -0,0 +1 @@ +queries/security/cwe-079/StoredXSS.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-079/UnsafeHtmlConstruction.expected b/PR_10_ruby/codeql_ruby/cwe-079/UnsafeHtmlConstruction.expected new file mode 100644 index 0000000..064d5a2 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/UnsafeHtmlConstruction.expected @@ -0,0 +1,16 @@ +edges +| lib/unsafeHtml.rb:2:31:2:34 | name | lib/unsafeHtml.rb:3:10:3:16 | #{...} | +| lib/unsafeHtml.rb:9:27:9:30 | name | lib/unsafeHtml.rb:11:13:11:19 | #{...} | +| lib/unsafeHtml.rb:16:19:16:22 | name | lib/unsafeHtml.rb:17:28:17:31 | name | +nodes +| lib/unsafeHtml.rb:2:31:2:34 | name | semmle.label | name | +| lib/unsafeHtml.rb:3:10:3:16 | #{...} | semmle.label | #{...} | +| lib/unsafeHtml.rb:9:27:9:30 | name | semmle.label | name | +| lib/unsafeHtml.rb:11:13:11:19 | #{...} | semmle.label | #{...} | +| lib/unsafeHtml.rb:16:19:16:22 | name | semmle.label | name | +| lib/unsafeHtml.rb:17:28:17:31 | name | semmle.label | name | +subpaths +#select +| lib/unsafeHtml.rb:3:10:3:16 | #{...} | lib/unsafeHtml.rb:2:31:2:34 | name | lib/unsafeHtml.rb:3:10:3:16 | #{...} | This string interpolation which depends on $@ might later allow $@. | lib/unsafeHtml.rb:2:31:2:34 | name | library input | lib/unsafeHtml.rb:3:5:3:22 | "

#{...}

" | cross-site scripting | +| lib/unsafeHtml.rb:11:13:11:19 | #{...} | lib/unsafeHtml.rb:9:27:9:30 | name | lib/unsafeHtml.rb:11:13:11:19 | #{...} | This string interpolation which depends on $@ might later allow $@. | lib/unsafeHtml.rb:9:27:9:30 | name | library input | lib/unsafeHtml.rb:13:5:13:5 | h | cross-site scripting | +| lib/unsafeHtml.rb:17:28:17:31 | name | lib/unsafeHtml.rb:16:19:16:22 | name | lib/unsafeHtml.rb:17:28:17:31 | name | This string format which depends on $@ might later allow $@. | lib/unsafeHtml.rb:16:19:16:22 | name | library input | lib/unsafeHtml.rb:17:5:17:32 | call to sprintf | cross-site scripting | diff --git a/PR_10_ruby/codeql_ruby/cwe-079/UnsafeHtmlConstruction.qlref b/PR_10_ruby/codeql_ruby/cwe-079/UnsafeHtmlConstruction.qlref new file mode 100644 index 0000000..ae814bc --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/UnsafeHtmlConstruction.qlref @@ -0,0 +1 @@ +queries/security/cwe-079/UnsafeHtmlConstruction.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-079/app/controllers/foo/bars_controller.rb b/PR_10_ruby/codeql_ruby/cwe-079/app/controllers/foo/bars_controller.rb new file mode 100644 index 0000000..4452fbf --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/app/controllers/foo/bars_controller.rb @@ -0,0 +1,41 @@ +class BarsController < ApplicationController + helper_method :user_name, :user_name_memo + + def index + render template: "foo/bars/index" + end + + def user_name + return params[:user_name] + end + + def user_name_memo + @user_name ||= params[:user_name] + end + + def show + @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]) +# {fact rule=autoescape-disabled@v1.0 defects=0} + + @header_escaped = ERB::Util.html_escape(cookies[:foo]) # OK - cookies not controllable by 3rd party + +# {/fact} + response.header["content-type"] = params[:content_type] +# {fact rule=autoescape-disabled@v1.0 defects=0} + + response.header["x-customer-header"] = params[:bar] # OK - header not relevant to XSS + +# {/fact} + render "foo/bars/show", locals: { display_text: dt, safe_text: "hello" } + end + + def make_safe_html + str = params[:user_name] + str.html_safe + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-079/app/controllers/foo/stores_controller.rb b/PR_10_ruby/codeql_ruby/cwe-079/app/controllers/foo/stores_controller.rb new file mode 100644 index 0000000..6dbb250 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/app/controllers/foo/stores_controller.rb @@ -0,0 +1,15 @@ +class StoresController < ApplicationController + helper_method :user_handle + def user_handle + User.find(1).handle + end + + def show + dt = File.read("foo.txt") + @instance_text = dt + @user = User.find 1 + @safe_user_handle = ERB::Util.html_escape(@user.handle) + @other_user_raw_name = User.find(2).raw_name + render "foo/stores/show", locals: { display_text: dt, safe_text: "hello" } + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-079/app/models/user.rb b/PR_10_ruby/codeql_ruby/cwe-079/app/models/user.rb new file mode 100644 index 0000000..1235ccb --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/app/models/user.rb @@ -0,0 +1,14 @@ +class User < ActiveRecord::Base + def is_dummy_user? + self.user_id == 0 + end + + def raw_name + me = self + me.handle + end + + def display_name + self.real_name || self.handle + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/_widget.html.erb b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/_widget.html.erb new file mode 100644 index 0000000..54b52af --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/_widget.html.erb @@ -0,0 +1,11 @@ +<%# BAD: A local rendered raw as an instance variable %> +<%= raw @display_text %> + +<%# BAD: A local rendered raw as a local variable %> +<%= raw display_text %> + +<%# BAD: A local rendered raw via the local_assigns hash %> +<%= raw local_assigns[:display_text] %> + +<%# GOOD: A local rendered with default escaping via the local_assigns hash %> +<%= local_assigns[:display_text] %> diff --git a/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/show.html.erb b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/show.html.erb new file mode 100644 index 0000000..be1ae02 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/show.html.erb @@ -0,0 +1,79 @@ +<%# BAD: An instance variable rendered without escaping %> +website + +<%# BAD: A local rendered raw as a local variable %> +<%= raw display_text %> + +<%# BAD: A local rendered raw via the local_assigns hash %> +<%= raw local_assigns[:display_text] %> + +<% key = :display_text %> +<%# BAD: A local rendered raw via the locals_assigns hash %> +<%= raw local_assigns[key] %> + + + +<%# GOOD: A local rendered with default escaping via the local_assigns hash %> +<%= local_assigns[display_text] %> + +<%# GOOD: default escaping of rendered text %> +<%= + full_text = prefix + local_assigns[:display_text] + full_text +%> + +<%# GOOD: default escaping of rendered text (from instance var) %> +<%= @instance_text %> + +<%# BAD: html_safe marks string as not requiring HTML escaping %> +<%= + display_text.html_safe +%> + +<%# BAD: html_safe marks string as not requiring HTML escaping %> +<%= + @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 %> + +<%# 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 %> + +<%# BAD: unsanitized user-input should not be passed to link_to as the URL %> +<%= 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 %> + user website +<% end %> + +<%# GOOD: @safe_foo is a hardcoded string here at runtime %> +<%= @safe_foo.html_safe %> + +<%# GOOD: @html_escaped is manually escaped in the controller %> +<%= @html_escaped.html_safe %> + +<%# GOOD: @html_escaped is manually escaped in the controller %> +<%= + html_escaped_in_template = h params[:text] + html_escaped_in_template.html_safe +%> + +<%# BAD: simple_format called with sanitize: false %> +<%= simple_format(params[:comment], sanitize: false) %> + +<%# BAD: javasript_include_tag called with remote input %> +<%= javascript_include_tag params[:url] %> + +<%# GOOD: input is sanitized %> +<%= sanitize(params[:comment]).html_safe %> diff --git a/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/show_unused.html.erb b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/show_unused.html.erb new file mode 100644 index 0000000..35ad37d --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/bars/show_unused.html.erb @@ -0,0 +1,5 @@ +<%# This file is not rendered. There should be no flow into it. %> + +<%= display_text.html_safe %> +<%= local_assigns[:display_text].html_safe %> +<%= @instance_text.html_safe %> diff --git a/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/stores/show.html.erb b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/stores/show.html.erb new file mode 100644 index 0000000..d8afec1 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/stores/show.html.erb @@ -0,0 +1,90 @@ +<%# BAD: A local rendered raw as a local variable %> +<%= raw display_text %> + +<%# BAD: A local rendered raw via the local_assigns hash %> +<%= raw local_assigns[:display_text] %> + +<% key = :display_text %> +<%# BAD: A local rendered raw via the locals_assigns hash %> +<%= raw local_assigns[key] %> + + + +<%# GOOD: A local rendered with default escaping via the local_assigns hash %> +<%= local_assigns[display_text] %> + +<%# GOOD: default escaping of rendered text %> +<%= + full_text = prefix + local_assigns[:display_text] + full_text +%> + +<%# GOOD: default escaping of rendered text (from instance var) %> +<%= @instance_text %> + +<%# BAD: html_safe marks string as not requiring HTML escaping %> +<%= + display_text.html_safe +%> + +<%# BAD: html_safe marks string as not requiring HTML escaping %> +<%= + @instance_text.html_safe +%> + +<%= render partial: 'foo/bars/widget', locals: { display_text: "widget_" + display_text } %> + +<%# BAD: user_name_handle is a helper method that returns unsanitized database content %> +<%= user_name_handle.html_safe %> + +<%# BAD: Direct to a database value without escaping %> +<%= @user.handle.html_safe %> + +<%# BAD: Indirect to a database value without escaping %> +<%= @user.raw_name.html_safe %> + +<%# GOOD: Direct to a database value with escaping %> +<%= @user.handle %> + +<%# GOOD: @safe_user_handle is manually escaped in the controller %> +<%= @safe_user_handle %> + +<%# GOOD: object_id is a built-in method, not an ORM access method %> +<%= @user.object_id.html_safe %> + +<%# BAD: Direct to a database value without escaping %> +<%= + some_user = User.find 1 + some_user.handle.html_safe +%> + +<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %> +<%= + some_user = User.find 1 + some_user.raw_name.html_safe +%> + +<%# GOOD: Direct to a database value with escaping %> +<%= + some_user = User.find 1 + some_user.handle +%> + +<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %> +<%= @user.display_name.html_safe %> + +<%# BAD: Indirect to a database value without escaping (currently missed due to lack of 'self' handling in ORM tracking) %> +<%= @other_user_raw_name.html_safe %> + +<%# BAD: Kernel.sprintf is a taint-step %> +<%= + sprintf("%s", @user.handle).html_safe +%> + +<%# GOOD: The `foo.bar.baz` is not recognized as a source %> +<%= @other_user_raw_name.foo.bar.baz.html_safe %> diff --git a/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/stores/show_unused.html.erb b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/stores/show_unused.html.erb new file mode 100644 index 0000000..35ad37d --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/app/views/foo/stores/show_unused.html.erb @@ -0,0 +1,5 @@ +<%# This file is not rendered. There should be no flow into it. %> + +<%= display_text.html_safe %> +<%= local_assigns[:display_text].html_safe %> +<%= @instance_text.html_safe %> diff --git a/PR_10_ruby/codeql_ruby/cwe-079/lib/unsafeHtml.rb b/PR_10_ruby/codeql_ruby/cwe-079/lib/unsafeHtml.rb new file mode 100644 index 0000000..772c989 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/lib/unsafeHtml.rb @@ -0,0 +1,42 @@ +class Foobar + def create_user_description(name) +# {fact rule=autoescape-disabled@v1.0 defects=1} + + "

#{name}

".html_safe # NOT OK - the parameter is not escaped + +# {/fact} + + # escape +# {fact rule=autoescape-disabled@v1.0 defects=0} + + "

#{ERB::Util.html_escape(name)}

".html_safe # OK - the parameter is escaped + +# {/fact} + end + + def string_like_literal name + h = <<-HTML +

#{name}

+ HTML +# {fact rule=autoescape-disabled@v1.0 defects=1} + + h.html_safe # NOT OK - the parameter is not escaped + +# {/fact} + end + + def sprintf_use name +# {fact rule=autoescape-disabled@v1.0 defects=1} + + sprintf("

%s

", name).html_safe # NOT OK - the parameter is not escaped + +# {/fact} + + # escape +# {fact rule=autoescape-disabled@v1.0 defects=0} + + sprintf("

%s

", ERB::Util.html_escape(name)).html_safe # OK - the parameter is escaped + +# {/fact} + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-079/unsafe-html.gemspec b/PR_10_ruby/codeql_ruby/cwe-079/unsafe-html.gemspec new file mode 100644 index 0000000..c574d71 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-079/unsafe-html.gemspec @@ -0,0 +1,5 @@ +Gem::Specification.new do |s| + s.name = 'unsafe-html' + s.require_path = "lib" + end + \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-089/ActiveRecordInjection.rb b/PR_10_ruby/codeql_ruby/cwe-089/ActiveRecordInjection.rb new file mode 100644 index 0000000..259ca32 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-089/ActiveRecordInjection.rb @@ -0,0 +1,278 @@ +class UserGroup < ActiveRecord::Base + has_many :users +end + +class User < ApplicationRecord + belongs_to :user_group + + def self.authenticate(name, pass) +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: possible untrusted input interpolated into SQL fragment + + + find(:first, :conditions => "name='#{name}' and pass='#{pass}'") + end +# {/fact} + + def self.from(user_group_id) +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: `find_by` with hash argument + + UserGroup.find_by(id: user_group_id).users + end +end +# {/fact} + +class Admin < User + def self.delete_by(condition = nil) +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # 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) + end +end +# {/fact} + +class FooController < ActionController::Base + + MAX_USER_ID = 100_000 + + # A string tainted by user input is inserted into an SQL query + def some_request_handler +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `SELECT AVG(#{params[:column]}) FROM "users"` + + # where `params[:column]` is unsanitized + User.calculate(:average, params[:column]) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `SELECT MAX(#{params[:column]}) FROM "users"` + + # where `params[:column]` is unsanitized + User.maximum(params[:column]) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `DELETE FROM "users" WHERE (id = '#{params[:id]}')` + + # where `params[:id]` is unsanitized + User.delete_by("id = '#{params[:id]}'") +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `DELETE FROM "users" WHERE (id = '#{params[:id]}')` + + # where `params[:id]` is unsanitized + # (in Rails < 4.0) + User.delete_all("id = '#{params[:id]}'") +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `SELECT "users".* FROM "users" WHERE (id = '#{params[:id]}')` + + # where `params[:id]` is unsanitized + User.destroy_by(["id = '#{params[:id]}'"]) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # 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]}'"]) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # 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) + id BETWEEN '#{params[:min_id]}' AND ? + SQL +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # 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]}'") + + User.authenticate(params[:name], params[:pass]) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # 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]}'") +# {/fact} + + user = User.first +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `SELECT "users".* FROM "users" WHERE id = 1 LIMIT 1 #{params[:lock]}` + + # where `params[:lock]` is unsanitized + user.reload(lock: params[:lock]) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `SELECT #{params[:column]} FROM "users"` + + # where `params[:column]` is unsanitized + User.select(params[:column]) + User.reselect(params[:column]) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `SELECT "users".* FROM "users" WHERE (#{params[:condition]})` + + # where `params[:condition]` is unsanitized + User.rewhere(params[:condition]) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `UPDATE "users" SET #{params[:fields]}` + + # where `params[:fields]` is unsanitized + User.update_all(params[:fields]) + + User.reorder(params[:direction]) + + User.count_by_sql(params[:custom_sql_query]) + end +end +# {/fact} + +class BarController < ApplicationController + def some_other_request_handler + ps = params + uid = ps[:id] + uidEq = "= '#{uid}'" + +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: executes `DELETE FROM "users" WHERE (id = #{uid})` + + # where `uid` is unsantized + User.delete_by("id " + uidEq) + end +# {/fact} + + def safe_paths + dir = params[:order] +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: barrier guard prevents taint flow + + if dir == "ASC" + User.order("name #{dir}") + else + dir = "DESC" + User.order("name #{dir}") + end + # TODO: a more idiomatic form of this guard is the following: + # dir = "DESC" unless dir == "ASC" + # but our taint tracking can't (yet) handle that properly + + name = params[:user_name] +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: barrier guard prevents taint flow + + + if %w(alice bob charlie).include? name + User.find_by("username = #{name}") + end +# {/fact} + name = params[:user_name] +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: hash arguments are sanitized by ActiveRecord + + + User.find_by(user_name: name) +# {/fact} + +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # OK: `find` method is overridden in `User` + + + User.find(params[:user_group]) + end +# {/fact} +end + +class BazController < BarController + def yet_another_handler + Admin.delete_by(params[:admin_condition]) + end +end + +class AnnotatedController < ActionController::Base + def index + name = params[:user_name] +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: string literal arguments not controlled by user are safe for annotations + + + users = User.annotate("this is a safe annotation").find_by(user_name: name) + end +# {/fact} + + def unsafe_action + name = params[:user_name] +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # 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) + end +# {/fact} +end + +# A regression test + +class Regression < ActiveRecord::Base +end + +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) + end + + + def permitted_params + 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]}") + Regression.connection.execute("SELECT * FROM users WHERE id = #{permitted_params[:user_id]}") + end +end \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-089/ArelInjection.rb b/PR_10_ruby/codeql_ruby/cwe-089/ArelInjection.rb new file mode 100644 index 0000000..4cbea89 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-089/ArelInjection.rb @@ -0,0 +1,11 @@ + +class PotatoController < ActionController::Base + def unsafe_action + name = params[:user_name] +# {fact rule=cross-site-scripting@v1.0 defects=1} + # BAD: SQL statement constructed from user input + + sql = Arel.sql("SELECT * FROM users WHERE name = #{name}") + end +# {/fact} +end \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-089/PgInjection.rb b/PR_10_ruby/codeql_ruby/cwe-089/PgInjection.rb new file mode 100644 index 0000000..2239b00 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-089/PgInjection.rb @@ -0,0 +1,99 @@ +require 'pg' + +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] + + # Establish a connection to a PostgreSQL database + conn = PG::Connection.open(:dbname => 'postgresql', :user => 'user', :password => 'pass', :host => 'localhost', :port => '5432') + + # .exec() and .async_exec() +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: SQL statement constructed from user input + + + qry1 = "SELECT * FROM users WHERE username = '#{name}';" + conn.exec(qry1) + conn.async_exec(qry1) +# {/fact} + # .exec_params() and .async_exec_params() +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: SQL statement constructed from user input + + qry2 = "SELECT * FROM users WHERE username = '#{name}';" + conn.exec_params(qry2) + conn.async_exec_params(qry2) +# {/fact} + + # .exec_params() and .async_exec_params() +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: SQL statement constructed from sanitized user input + + qry2 = "SELECT * FROM users WHERE username = $1;" + conn.exec_params(qry2, [name]) + conn.async_exec_params(qry2, [name]) +# {/fact} + + # .prepare() and .exec_prepared() +# {fact rule=cross-site-scripting@v1.0 defects=1} + + # BAD: SQL statement constructed from user input + + qry3 = "SELECT * FROM users WHERE username = '#{name}';" + conn.prepare("query_1", qry3) + conn.exec_prepared('query_1') +# {/fact} + + # .prepare() and .exec_prepared() +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: SQL statement constructed from sanitized user input + + qry3 = "SELECT * FROM users WHERE username = $1;" + conn.prepare("query_2", qry3) + conn.exec_prepared('query_2', [name]) + + # .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) + end +# {/fact} +end + +class BarController < ApplicationController + def safe_paths + name1 = params["name1"] +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: barrier guard prevents taint flow + + if name == "admin" + qry_bar1 = "SELECT * FROM users WHERE username = '%s';" % name + else + qry_bar1 = "SELECT * FROM users WHERE username = 'none';" + end + conn.exec_params(qry_bar1) +# {/fact} + + name2 = params["name2"] +# {fact rule=cross-site-scripting@v1.0 defects=0} + + # GOOD: barrier guard prevents taint flow + + name2 = if ["admin", "guest"].include? name2 + name2 + else + name2 = "none" + end + qry_bar2 = "SELECT * FROM users WHERE username = '%s';" % name + conn.exec_params(qry_bar2) + end +# {/fact} +end diff --git a/PR_10_ruby/codeql_ruby/cwe-089/SqlInjection.expected b/PR_10_ruby/codeql_ruby/cwe-089/SqlInjection.expected new file mode 100644 index 0000000..161cdcc --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-089/SqlInjection.expected @@ -0,0 +1,199 @@ +edges +| ActiveRecordInjection.rb:8:25:8:28 | name | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | +| ActiveRecordInjection.rb:8:31:8:34 | pass | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | +| ActiveRecordInjection.rb:20:22:20:30 | condition | ActiveRecordInjection.rb:23:16:23:24 | condition | +| ActiveRecordInjection.rb:35:30:35:35 | call to params | ActiveRecordInjection.rb:35:30:35:44 | ...[...] | +| ActiveRecordInjection.rb:39:18:39:23 | call to params | ActiveRecordInjection.rb:39:18:39:32 | ...[...] | +| ActiveRecordInjection.rb:43:29:43:34 | call to params | ActiveRecordInjection.rb:43:29:43:39 | ...[...] | +| ActiveRecordInjection.rb:43:29:43:39 | ...[...] | ActiveRecordInjection.rb:43:20:43:42 | "id = '#{...}'" | +| ActiveRecordInjection.rb:48:30:48:35 | call to params | ActiveRecordInjection.rb:48:30:48:40 | ...[...] | +| ActiveRecordInjection.rb:48:30:48:40 | ...[...] | ActiveRecordInjection.rb:48:21:48:43 | "id = '#{...}'" | +| ActiveRecordInjection.rb:52:31:52:36 | call to params | ActiveRecordInjection.rb:52:31:52:41 | ...[...] | +| ActiveRecordInjection.rb:52:31:52:41 | ...[...] | ActiveRecordInjection.rb:52:22:52:44 | "id = '#{...}'" | +| ActiveRecordInjection.rb:57:32:57:37 | call to params | ActiveRecordInjection.rb:57:32:57:42 | ...[...] | +| ActiveRecordInjection.rb:57:32:57:42 | ...[...] | ActiveRecordInjection.rb:57:23:57:45 | "id = '#{...}'" | +| ActiveRecordInjection.rb:62:21:62:26 | call to params | ActiveRecordInjection.rb:62:21:62:35 | ...[...] | +| ActiveRecordInjection.rb:62:21:62:35 | ...[...] | ActiveRecordInjection.rb:61:16:61:21 | <<-SQL | +| ActiveRecordInjection.rb:68:34:68:39 | call to params | ActiveRecordInjection.rb:68:34:68:44 | ...[...] | +| ActiveRecordInjection.rb:68:34:68:44 | ...[...] | ActiveRecordInjection.rb:68:20:68:47 | "user.id = '#{...}'" | +| ActiveRecordInjection.rb:70:23:70:28 | call to params | ActiveRecordInjection.rb:70:23:70:35 | ...[...] | +| ActiveRecordInjection.rb:70:23:70:35 | ...[...] | ActiveRecordInjection.rb:8:25:8:28 | name | +| ActiveRecordInjection.rb:70:38:70:43 | call to params | ActiveRecordInjection.rb:70:38:70:50 | ...[...] | +| ActiveRecordInjection.rb:70:38:70:50 | ...[...] | ActiveRecordInjection.rb:8:31:8:34 | pass | +| ActiveRecordInjection.rb:74:41:74:46 | call to params | ActiveRecordInjection.rb:74:41:74:51 | ...[...] | +| ActiveRecordInjection.rb:74:41:74:51 | ...[...] | ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | +| ActiveRecordInjection.rb:79:23:79:28 | call to params | ActiveRecordInjection.rb:79:23:79:35 | ...[...] | +| ActiveRecordInjection.rb:83:17:83:22 | call to params | ActiveRecordInjection.rb:83:17:83:31 | ...[...] | +| ActiveRecordInjection.rb:84:19:84:24 | call to params | ActiveRecordInjection.rb:84:19:84:33 | ...[...] | +| ActiveRecordInjection.rb:88:18:88:23 | call to params | ActiveRecordInjection.rb:88:18:88:35 | ...[...] | +| ActiveRecordInjection.rb:92:21:92:26 | call to params | ActiveRecordInjection.rb:92:21:92:35 | ...[...] | +| ActiveRecordInjection.rb:94:18:94:23 | call to params | ActiveRecordInjection.rb:94:18:94:35 | ...[...] | +| ActiveRecordInjection.rb:96:23:96:28 | call to params | ActiveRecordInjection.rb:96:23:96:47 | ...[...] | +| ActiveRecordInjection.rb:102:5:102:6 | ps | ActiveRecordInjection.rb:103:11:103:12 | ps | +| ActiveRecordInjection.rb:102:10:102:15 | call to params | ActiveRecordInjection.rb:102:5:102:6 | ps | +| ActiveRecordInjection.rb:103:5:103:7 | uid | ActiveRecordInjection.rb:104:5:104:9 | uidEq | +| ActiveRecordInjection.rb:103:11:103:12 | ps | ActiveRecordInjection.rb:103:11:103:17 | ...[...] | +| ActiveRecordInjection.rb:103:11:103:17 | ...[...] | ActiveRecordInjection.rb:103:5:103:7 | uid | +| ActiveRecordInjection.rb:104:5:104:9 | uidEq | ActiveRecordInjection.rb:108:20:108:32 | ... + ... | +| ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | +| ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | +| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | ActiveRecordInjection.rb:20:22:20:30 | condition | +| ActiveRecordInjection.rb:155:59:155:64 | call to params | ActiveRecordInjection.rb:155:59:155:74 | ...[...] | +| ActiveRecordInjection.rb:155:59:155:74 | ...[...] | ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | +| ActiveRecordInjection.rb:166:5:166:13 | my_params | ActiveRecordInjection.rb:167:47:167:55 | my_params | +| ActiveRecordInjection.rb:166:17:166:32 | call to permitted_params | ActiveRecordInjection.rb:166:5:166:13 | my_params | +| ActiveRecordInjection.rb:167:5:167:9 | query | ActiveRecordInjection.rb:168:37:168:41 | query | +| ActiveRecordInjection.rb:167:47:167:55 | my_params | ActiveRecordInjection.rb:167:47:167:65 | ...[...] | +| ActiveRecordInjection.rb:167:47:167:65 | ...[...] | ActiveRecordInjection.rb:167:5:167:9 | query | +| ActiveRecordInjection.rb:173:5:173:10 | call to params | ActiveRecordInjection.rb:173:5:173:27 | call to require | +| ActiveRecordInjection.rb:173:5:173:27 | call to require | ActiveRecordInjection.rb:173:5:173:59 | call to permit | +| ActiveRecordInjection.rb:173:5:173:59 | call to permit | ActiveRecordInjection.rb:166:17:166:32 | call to permitted_params | +| ActiveRecordInjection.rb:173:5:173:59 | call to permit | ActiveRecordInjection.rb:177:77:177:92 | call to permitted_params | +| ActiveRecordInjection.rb:173:5:173:59 | call to permit | ActiveRecordInjection.rb:178:69:178:84 | call to permitted_params | +| ActiveRecordInjection.rb:177:77:177:92 | call to permitted_params | ActiveRecordInjection.rb:177:77:177:102 | ...[...] | +| ActiveRecordInjection.rb:177:77:177:102 | ...[...] | ActiveRecordInjection.rb:177:43:177:104 | "SELECT * FROM users WHERE id ..." | +| ActiveRecordInjection.rb:178:69:178:84 | call to permitted_params | ActiveRecordInjection.rb:178:69:178:94 | ...[...] | +| ActiveRecordInjection.rb:178:69:178:94 | ...[...] | ActiveRecordInjection.rb:178:35:178:96 | "SELECT * FROM users WHERE id ..." | +| ArelInjection.rb:4:5:4:8 | name | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | +| ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:4:12:4:29 | ...[...] | +| ArelInjection.rb:4:12:4:29 | ...[...] | ArelInjection.rb:4:5:4:8 | name | +| PgInjection.rb:6:5:6:8 | name | PgInjection.rb:13:5:13:8 | qry1 | +| PgInjection.rb:6:5:6:8 | name | PgInjection.rb:19:5:19:8 | qry2 | +| PgInjection.rb:6:5:6:8 | name | PgInjection.rb:31:5:31:8 | qry3 | +| PgInjection.rb:6:5:6:8 | name | PgInjection.rb:43:5:43:8 | qry3 | +| PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:6:12:6:24 | ...[...] | +| PgInjection.rb:6:12:6:24 | ...[...] | PgInjection.rb:6:5:6:8 | name | +| PgInjection.rb:13:5:13:8 | qry1 | PgInjection.rb:14:15:14:18 | qry1 | +| PgInjection.rb:13:5:13:8 | qry1 | PgInjection.rb:15:21:15:24 | qry1 | +| PgInjection.rb:19:5:19:8 | qry2 | PgInjection.rb:20:22:20:25 | qry2 | +| PgInjection.rb:19:5:19:8 | qry2 | PgInjection.rb:21:28:21:31 | qry2 | +| PgInjection.rb:31:5:31:8 | qry3 | PgInjection.rb:32:29:32:32 | qry3 | +| PgInjection.rb:43:5:43:8 | qry3 | PgInjection.rb:44:29:44:32 | qry3 | +nodes +| ActiveRecordInjection.rb:8:25:8:28 | name | semmle.label | name | +| ActiveRecordInjection.rb:8:31:8:34 | pass | semmle.label | pass | +| ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | semmle.label | "name='#{...}' and pass='#{...}'" | +| ActiveRecordInjection.rb:20:22:20:30 | condition | semmle.label | condition | +| ActiveRecordInjection.rb:23:16:23:24 | condition | semmle.label | condition | +| ActiveRecordInjection.rb:35:30:35:35 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:35:30:35:44 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:39:18:39:23 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:39:18:39:32 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:43:20:43:42 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | +| ActiveRecordInjection.rb:43:29:43:34 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:43:29:43:39 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:48:21:48:43 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | +| ActiveRecordInjection.rb:48:30:48:35 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:48:30:48:40 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:52:22:52:44 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | +| ActiveRecordInjection.rb:52:31:52:36 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:52:31:52:41 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:57:23:57:45 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | +| ActiveRecordInjection.rb:57:32:57:37 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:57:32:57:42 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:61:16:61:21 | <<-SQL | semmle.label | <<-SQL | +| ActiveRecordInjection.rb:62:21:62:26 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:62:21:62:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:68:20:68:47 | "user.id = '#{...}'" | semmle.label | "user.id = '#{...}'" | +| ActiveRecordInjection.rb:68:34:68:39 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:68:34:68:44 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:70:23:70:28 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:70:23:70:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:70:38:70:43 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:70:38:70:50 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | semmle.label | "id = '#{...}'" | +| ActiveRecordInjection.rb:74:41:74:46 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:74:41:74:51 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:79:23:79:28 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:79:23:79:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:83:17:83:22 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:83:17:83:31 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:84:19:84:24 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:84:19:84:33 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:88:18:88:23 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:88:18:88:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:92:21:92:26 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:92:21:92:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:94:18:94:23 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:94:18:94:35 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:96:23:96:28 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:96:23:96:47 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:102:5:102:6 | ps | semmle.label | ps | +| ActiveRecordInjection.rb:102:10:102:15 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:103:5:103:7 | uid | semmle.label | uid | +| ActiveRecordInjection.rb:103:11:103:12 | ps | semmle.label | ps | +| ActiveRecordInjection.rb:103:11:103:17 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:104:5:104:9 | uidEq | semmle.label | uidEq | +| ActiveRecordInjection.rb:108:20:108:32 | ... + ... | semmle.label | ... + ... | +| ActiveRecordInjection.rb:141:21:141:26 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | semmle.label | "this is an unsafe annotation:..." | +| ActiveRecordInjection.rb:155:59:155:64 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:155:59:155:74 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:166:5:166:13 | my_params | semmle.label | my_params | +| ActiveRecordInjection.rb:166:17:166:32 | call to permitted_params | semmle.label | call to permitted_params | +| ActiveRecordInjection.rb:167:5:167:9 | query | semmle.label | query | +| ActiveRecordInjection.rb:167:47:167:55 | my_params | semmle.label | my_params | +| ActiveRecordInjection.rb:167:47:167:65 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:168:37:168:41 | query | semmle.label | query | +| ActiveRecordInjection.rb:173:5:173:10 | call to params | semmle.label | call to params | +| ActiveRecordInjection.rb:173:5:173:27 | call to require | semmle.label | call to require | +| ActiveRecordInjection.rb:173:5:173:59 | call to permit | semmle.label | call to permit | +| ActiveRecordInjection.rb:177:43:177:104 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | +| ActiveRecordInjection.rb:177:77:177:92 | call to permitted_params | semmle.label | call to permitted_params | +| ActiveRecordInjection.rb:177:77:177:102 | ...[...] | semmle.label | ...[...] | +| ActiveRecordInjection.rb:178:35:178:96 | "SELECT * FROM users WHERE id ..." | semmle.label | "SELECT * FROM users WHERE id ..." | +| ActiveRecordInjection.rb:178:69:178:84 | call to permitted_params | semmle.label | call to permitted_params | +| ActiveRecordInjection.rb:178:69:178:94 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:4:5:4:8 | name | semmle.label | name | +| ArelInjection.rb:4:12:4:17 | call to params | semmle.label | call to params | +| ArelInjection.rb:4:12:4:29 | ...[...] | semmle.label | ...[...] | +| ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | semmle.label | "SELECT * FROM users WHERE nam..." | +| PgInjection.rb:6:5:6:8 | name | semmle.label | name | +| PgInjection.rb:6:12:6:17 | call to params | semmle.label | call to params | +| PgInjection.rb:6:12:6:24 | ...[...] | semmle.label | ...[...] | +| PgInjection.rb:13:5:13:8 | qry1 | semmle.label | qry1 | +| PgInjection.rb:14:15:14:18 | qry1 | semmle.label | qry1 | +| PgInjection.rb:15:21:15:24 | qry1 | semmle.label | qry1 | +| PgInjection.rb:19:5:19:8 | qry2 | semmle.label | qry2 | +| PgInjection.rb:20:22:20:25 | qry2 | semmle.label | qry2 | +| PgInjection.rb:21:28:21:31 | qry2 | semmle.label | qry2 | +| PgInjection.rb:31:5:31:8 | qry3 | semmle.label | qry3 | +| PgInjection.rb:32:29:32:32 | qry3 | semmle.label | qry3 | +| PgInjection.rb:43:5:43:8 | qry3 | semmle.label | qry3 | +| PgInjection.rb:44:29:44:32 | qry3 | semmle.label | qry3 | +subpaths +#select +| ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:70:23:70:28 | call to params | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:70:23:70:28 | call to params | user-provided value | +| ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | ActiveRecordInjection.rb:70:38:70:43 | call to params | ActiveRecordInjection.rb:10:33:10:67 | "name='#{...}' and pass='#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:70:38:70:43 | call to params | user-provided value | +| ActiveRecordInjection.rb:23:16:23:24 | condition | ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:23:16:23:24 | condition | This SQL query depends on a $@. | ActiveRecordInjection.rb:141:21:141:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:35:30:35:44 | ...[...] | ActiveRecordInjection.rb:35:30:35:35 | call to params | ActiveRecordInjection.rb:35:30:35:44 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:35:30:35:35 | call to params | user-provided value | +| ActiveRecordInjection.rb:39:18:39:32 | ...[...] | ActiveRecordInjection.rb:39:18:39:23 | call to params | ActiveRecordInjection.rb:39:18:39:32 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:39:18:39:23 | call to params | user-provided value | +| ActiveRecordInjection.rb:43:20:43:42 | "id = '#{...}'" | ActiveRecordInjection.rb:43:29:43:34 | call to params | ActiveRecordInjection.rb:43:20:43:42 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:43:29:43:34 | call to params | user-provided value | +| ActiveRecordInjection.rb:48:21:48:43 | "id = '#{...}'" | ActiveRecordInjection.rb:48:30:48:35 | call to params | ActiveRecordInjection.rb:48:21:48:43 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:48:30:48:35 | call to params | user-provided value | +| ActiveRecordInjection.rb:52:22:52:44 | "id = '#{...}'" | ActiveRecordInjection.rb:52:31:52:36 | call to params | ActiveRecordInjection.rb:52:22:52:44 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:52:31:52:36 | call to params | user-provided value | +| ActiveRecordInjection.rb:57:23:57:45 | "id = '#{...}'" | ActiveRecordInjection.rb:57:32:57:37 | call to params | ActiveRecordInjection.rb:57:23:57:45 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:57:32:57:37 | call to params | user-provided value | +| ActiveRecordInjection.rb:61:16:61:21 | <<-SQL | ActiveRecordInjection.rb:62:21:62:26 | call to params | ActiveRecordInjection.rb:61:16:61:21 | <<-SQL | This SQL query depends on a $@. | ActiveRecordInjection.rb:62:21:62:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:68:20:68:47 | "user.id = '#{...}'" | ActiveRecordInjection.rb:68:34:68:39 | call to params | ActiveRecordInjection.rb:68:20:68:47 | "user.id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:68:34:68:39 | call to params | user-provided value | +| ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | ActiveRecordInjection.rb:74:41:74:46 | call to params | ActiveRecordInjection.rb:74:32:74:54 | "id = '#{...}'" | This SQL query depends on a $@. | ActiveRecordInjection.rb:74:41:74:46 | call to params | user-provided value | +| ActiveRecordInjection.rb:79:23:79:35 | ...[...] | ActiveRecordInjection.rb:79:23:79:28 | call to params | ActiveRecordInjection.rb:79:23:79:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:79:23:79:28 | call to params | user-provided value | +| ActiveRecordInjection.rb:83:17:83:31 | ...[...] | ActiveRecordInjection.rb:83:17:83:22 | call to params | ActiveRecordInjection.rb:83:17:83:31 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:83:17:83:22 | call to params | user-provided value | +| ActiveRecordInjection.rb:84:19:84:33 | ...[...] | ActiveRecordInjection.rb:84:19:84:24 | call to params | ActiveRecordInjection.rb:84:19:84:33 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:84:19:84:24 | call to params | user-provided value | +| ActiveRecordInjection.rb:88:18:88:35 | ...[...] | ActiveRecordInjection.rb:88:18:88:23 | call to params | ActiveRecordInjection.rb:88:18:88:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:88:18:88:23 | call to params | user-provided value | +| ActiveRecordInjection.rb:92:21:92:35 | ...[...] | ActiveRecordInjection.rb:92:21:92:26 | call to params | ActiveRecordInjection.rb:92:21:92:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:92:21:92:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:94:18:94:35 | ...[...] | ActiveRecordInjection.rb:94:18:94:23 | call to params | ActiveRecordInjection.rb:94:18:94:35 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:94:18:94:23 | call to params | user-provided value | +| ActiveRecordInjection.rb:96:23:96:47 | ...[...] | ActiveRecordInjection.rb:96:23:96:28 | call to params | ActiveRecordInjection.rb:96:23:96:47 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:96:23:96:28 | call to params | user-provided value | +| ActiveRecordInjection.rb:108:20:108:32 | ... + ... | ActiveRecordInjection.rb:102:10:102:15 | call to params | ActiveRecordInjection.rb:108:20:108:32 | ... + ... | This SQL query depends on a $@. | ActiveRecordInjection.rb:102:10:102:15 | call to params | user-provided value | +| ActiveRecordInjection.rb:141:21:141:44 | ...[...] | ActiveRecordInjection.rb:141:21:141:26 | call to params | ActiveRecordInjection.rb:141:21:141:44 | ...[...] | This SQL query depends on a $@. | ActiveRecordInjection.rb:141:21:141:26 | call to params | user-provided value | +| ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | ActiveRecordInjection.rb:155:59:155:64 | call to params | ActiveRecordInjection.rb:155:27:155:76 | "this is an unsafe annotation:..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:155:59:155:64 | call to params | user-provided value | +| ActiveRecordInjection.rb:168:37:168:41 | query | ActiveRecordInjection.rb:173:5:173:10 | call to params | ActiveRecordInjection.rb:168:37:168:41 | query | This SQL query depends on a $@. | ActiveRecordInjection.rb:173:5:173:10 | call to params | user-provided value | +| ActiveRecordInjection.rb:177:43:177:104 | "SELECT * FROM users WHERE id ..." | ActiveRecordInjection.rb:173:5:173:10 | call to params | ActiveRecordInjection.rb:177:43:177:104 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:173:5:173:10 | call to params | user-provided value | +| ActiveRecordInjection.rb:178:35:178:96 | "SELECT * FROM users WHERE id ..." | ActiveRecordInjection.rb:173:5:173:10 | call to params | ActiveRecordInjection.rb:178:35:178:96 | "SELECT * FROM users WHERE id ..." | This SQL query depends on a $@. | ActiveRecordInjection.rb:173:5:173:10 | call to params | user-provided value | +| ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | ArelInjection.rb:4:12:4:17 | call to params | ArelInjection.rb:6:20:6:61 | "SELECT * FROM users WHERE nam..." | This SQL query depends on a $@. | ArelInjection.rb:4:12:4:17 | call to params | user-provided value | +| PgInjection.rb:14:15:14:18 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:14:15:14:18 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:15:21:15:24 | qry1 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:15:21:15:24 | qry1 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:20:22:20:25 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:20:22:20:25 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:21:28:21:31 | qry2 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:21:28:21:31 | qry2 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:32:29:32:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:32:29:32:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | +| PgInjection.rb:44:29:44:32 | qry3 | PgInjection.rb:6:12:6:17 | call to params | PgInjection.rb:44:29:44:32 | qry3 | This SQL query depends on a $@. | PgInjection.rb:6:12:6:17 | call to params | user-provided value | diff --git a/PR_10_ruby/codeql_ruby/cwe-089/SqlInjection.qlref b/PR_10_ruby/codeql_ruby/cwe-089/SqlInjection.qlref new file mode 100644 index 0000000..bcb55c8 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-089/SqlInjection.qlref @@ -0,0 +1 @@ +queries/security/cwe-089/SqlInjection.ql diff --git a/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.expected b/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.expected new file mode 100644 index 0000000..5212480 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.expected @@ -0,0 +1,105 @@ +edges +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:8:10:8:13 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:8:10:8:13 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:20:20:20:23 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:20:20:20:23 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:23:21:23:24 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:23:21:23:24 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:29:15:29:18 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:32:19:32:22 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:38:24:38:27 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:38:24:38:27 | code | +| CodeInjection.rb:5:5:5:8 | code | CodeInjection.rb:41:40:41:43 | code | +| CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:5:12:5:24 | ...[...] | +| CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:5:12:5:24 | ...[...] | +| CodeInjection.rb:5:12:5:24 | ...[...] | CodeInjection.rb:5:5:5:8 | code | +| CodeInjection.rb:5:12:5:24 | ...[...] | CodeInjection.rb:5:5:5:8 | code | +| CodeInjection.rb:38:24:38:27 | code | CodeInjection.rb:38:10:38:28 | call to escape | +| CodeInjection.rb:38:24:38:27 | code | CodeInjection.rb:38:10:38:28 | call to escape | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:80:16:80:19 | code | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:86:10:86:37 | ... + ... | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:90:10:90:13 | code | +| CodeInjection.rb:78:5:78:8 | code | CodeInjection.rb:90:10:90:13 | code | +| CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:78:12:78:24 | ...[...] | +| CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:78:12:78:24 | ...[...] | +| CodeInjection.rb:78:12:78:24 | ...[...] | CodeInjection.rb:78:5:78:8 | code | +| CodeInjection.rb:78:12:78:24 | ...[...] | CodeInjection.rb:78:5:78:8 | code | +| CodeInjection.rb:101:3:102:5 | self in index [@foo] | CodeInjection.rb:111:3:113:5 | self in baz [@foo] | +| CodeInjection.rb:101:3:102:5 | self in index [@foo] | CodeInjection.rb:111:3:113:5 | self in baz [@foo] | +| CodeInjection.rb:105:5:105:8 | [post] self [@foo] | CodeInjection.rb:108:3:109:5 | self in bar [@foo] | +| CodeInjection.rb:105:5:105:8 | [post] self [@foo] | CodeInjection.rb:108:3:109:5 | self in bar [@foo] | +| CodeInjection.rb:105:12:105:17 | call to params | CodeInjection.rb:105:12:105:23 | ...[...] | +| CodeInjection.rb:105:12:105:17 | call to params | CodeInjection.rb:105:12:105:23 | ...[...] | +| CodeInjection.rb:105:12:105:23 | ...[...] | CodeInjection.rb:105:5:105:8 | [post] self [@foo] | +| CodeInjection.rb:105:12:105:23 | ...[...] | CodeInjection.rb:105:5:105:8 | [post] self [@foo] | +| CodeInjection.rb:108:3:109:5 | self in bar [@foo] | CodeInjection.rb:101:3:102:5 | self in index [@foo] | +| CodeInjection.rb:108:3:109:5 | self in bar [@foo] | CodeInjection.rb:101:3:102:5 | self in index [@foo] | +| CodeInjection.rb:111:3:113:5 | self in baz [@foo] | CodeInjection.rb:112:10:112:13 | self [@foo] | +| CodeInjection.rb:111:3:113:5 | self in baz [@foo] | CodeInjection.rb:112:10:112:13 | self [@foo] | +| CodeInjection.rb:112:10:112:13 | self [@foo] | CodeInjection.rb:112:10:112:13 | @foo | +| CodeInjection.rb:112:10:112:13 | self [@foo] | CodeInjection.rb:112:10:112:13 | @foo | +nodes +| CodeInjection.rb:5:5:5:8 | code | semmle.label | code | +| CodeInjection.rb:5:5:5:8 | code | semmle.label | code | +| CodeInjection.rb:5:12:5:17 | call to params | semmle.label | call to params | +| CodeInjection.rb:5:12:5:17 | call to params | semmle.label | call to params | +| CodeInjection.rb:5:12:5:24 | ...[...] | semmle.label | ...[...] | +| CodeInjection.rb:5:12:5:24 | ...[...] | semmle.label | ...[...] | +| CodeInjection.rb:8:10:8:13 | code | semmle.label | code | +| CodeInjection.rb:8:10:8:13 | code | semmle.label | code | +| CodeInjection.rb:11:10:11:15 | call to params | semmle.label | call to params | +| CodeInjection.rb:11:10:11:15 | call to params | semmle.label | call to params | +| CodeInjection.rb:20:20:20:23 | code | semmle.label | code | +| CodeInjection.rb:20:20:20:23 | code | semmle.label | code | +| CodeInjection.rb:23:21:23:24 | code | semmle.label | code | +| CodeInjection.rb:23:21:23:24 | code | semmle.label | code | +| CodeInjection.rb:29:15:29:18 | code | semmle.label | code | +| CodeInjection.rb:32:19:32:22 | code | semmle.label | code | +| CodeInjection.rb:38:10:38:28 | call to escape | semmle.label | call to escape | +| CodeInjection.rb:38:10:38:28 | call to escape | semmle.label | call to escape | +| CodeInjection.rb:38:24:38:27 | code | semmle.label | code | +| CodeInjection.rb:38:24:38:27 | code | semmle.label | code | +| CodeInjection.rb:41:40:41:43 | code | semmle.label | code | +| CodeInjection.rb:78:5:78:8 | code | semmle.label | code | +| CodeInjection.rb:78:5:78:8 | code | semmle.label | code | +| CodeInjection.rb:78:12:78:17 | call to params | semmle.label | call to params | +| CodeInjection.rb:78:12:78:17 | call to params | semmle.label | call to params | +| CodeInjection.rb:78:12:78:24 | ...[...] | semmle.label | ...[...] | +| CodeInjection.rb:78:12:78:24 | ...[...] | semmle.label | ...[...] | +| CodeInjection.rb:80:16:80:19 | code | semmle.label | code | +| CodeInjection.rb:86:10:86:37 | ... + ... | semmle.label | ... + ... | +| CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | semmle.label | "prefix_#{...}_suffix" | +| CodeInjection.rb:90:10:90:13 | code | semmle.label | code | +| CodeInjection.rb:90:10:90:13 | code | semmle.label | code | +| CodeInjection.rb:101:3:102:5 | self in index [@foo] | semmle.label | self in index [@foo] | +| CodeInjection.rb:101:3:102:5 | self in index [@foo] | semmle.label | self in index [@foo] | +| CodeInjection.rb:105:5:105:8 | [post] self [@foo] | semmle.label | [post] self [@foo] | +| CodeInjection.rb:105:5:105:8 | [post] self [@foo] | semmle.label | [post] self [@foo] | +| CodeInjection.rb:105:12:105:17 | call to params | semmle.label | call to params | +| CodeInjection.rb:105:12:105:17 | call to params | semmle.label | call to params | +| CodeInjection.rb:105:12:105:23 | ...[...] | semmle.label | ...[...] | +| CodeInjection.rb:105:12:105:23 | ...[...] | semmle.label | ...[...] | +| CodeInjection.rb:108:3:109:5 | self in bar [@foo] | semmle.label | self in bar [@foo] | +| CodeInjection.rb:108:3:109:5 | self in bar [@foo] | semmle.label | self in bar [@foo] | +| CodeInjection.rb:111:3:113:5 | self in baz [@foo] | semmle.label | self in baz [@foo] | +| CodeInjection.rb:111:3:113:5 | self in baz [@foo] | semmle.label | self in baz [@foo] | +| CodeInjection.rb:112:10:112:13 | @foo | semmle.label | @foo | +| CodeInjection.rb:112:10:112:13 | @foo | semmle.label | @foo | +| CodeInjection.rb:112:10:112:13 | self [@foo] | semmle.label | self [@foo] | +| CodeInjection.rb:112:10:112:13 | self [@foo] | semmle.label | self [@foo] | +subpaths +#select +| CodeInjection.rb:8:10:8:13 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:8:10:8:13 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:11:10:11:15 | call to params | CodeInjection.rb:11:10:11:15 | call to params | CodeInjection.rb:11:10:11:15 | call to params | This code execution depends on a $@. | CodeInjection.rb:11:10:11:15 | call to params | user-provided value | +| CodeInjection.rb:20:20:20:23 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:20:20:20:23 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:23:21:23:24 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:23:21:23:24 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:29:15:29:18 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:29:15:29:18 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:32:19:32:22 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:32:19:32:22 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:38:10:38:28 | call to escape | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:38:10:38:28 | call to escape | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:41:40:41:43 | code | CodeInjection.rb:5:12:5:17 | call to params | CodeInjection.rb:41:40:41:43 | code | This code execution depends on a $@. | CodeInjection.rb:5:12:5:17 | call to params | user-provided value | +| CodeInjection.rb:80:16:80:19 | code | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:80:16:80:19 | code | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | +| CodeInjection.rb:86:10:86:37 | ... + ... | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:86:10:86:37 | ... + ... | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | +| CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:88:10:88:32 | "prefix_#{...}_suffix" | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | +| CodeInjection.rb:90:10:90:13 | code | CodeInjection.rb:78:12:78:17 | call to params | CodeInjection.rb:90:10:90:13 | code | This code execution depends on a $@. | CodeInjection.rb:78:12:78:17 | call to params | user-provided value | +| CodeInjection.rb:112:10:112:13 | @foo | CodeInjection.rb:105:12:105:17 | call to params | CodeInjection.rb:112:10:112:13 | @foo | This code execution depends on a $@. | CodeInjection.rb:105:12:105:17 | call to params | user-provided value | diff --git a/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.qlref b/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.qlref new file mode 100644 index 0000000..6dcbcb4 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.qlref @@ -0,0 +1 @@ +queries/security/cwe-094/CodeInjection.ql diff --git a/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.rb b/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.rb new file mode 100644 index 0000000..c8c5842 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-094/CodeInjection/CodeInjection.rb @@ -0,0 +1,199 @@ +require 'active_job' + +class UsersController < ActionController::Base + def create + code = params[:code] + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + # BAD + + + eval(code) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + # BAD + + + eval(params) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=0} + + # GOOD - user input is in second argument, which is not evaluated as Ruby code + + + send(:sanitize, params[:code]) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=0} + + # GOOD + + + Foo.new.bar(code) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + # BAD + + Foo.class_eval(code) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + # BAD + + + Foo.module_eval(code) +# {/fact} +'' +# {fact rule=autoescape-disabled@v1.0 defects=0} + + # GOOD + + + Bar.class_eval(code) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + # BAD + + + const_get(code) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + # BAD + + + Foo.const_get(code) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=0} + + # GOOD + + + Bar.const_get(code) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + # BAD + + + eval(Regexp.escape(code)) +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + # BAD + + ActiveJob::Serializers.deserialize(code) + end +# {/fact}' +' + def update +# {fact rule=autoescape-disabled@v1.0 defects=0} + + # GOOD + + eval("foo") + end +# {/fact} + private + + def sanitize(code) + true + end +end + +class Foo + def eval(x) + true + end + + def bar(x) + eval(x) + end +end + +class Bar + def self.class_eval(x) + true + end + + def self.const_get(x) + true + end +end + +class UsersController < ActionController::Base + def create + code = params[:code] + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + obj().send(code, "foo"); # BAD + +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=0} + + obj().send("prefix_" + code + "_suffix", "foo"); # GOOD + +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=0} + + obj().send("prefix_#{code}_suffix", "foo"); # GOOD + +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval("prefix_" + code + "_suffix"); # BAD + +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval("prefix_#{code}_suffix"); # BAD + +# {/fact} + +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(code); # BAD + +# {/fact} + end +end + +Rails.application.routes.draw { resources :posts } + +class PostsController < ActionController::Base + before_action :foo + before_action :bar + after_action :baz + + def index + end + + def foo + @foo = params[:foo] + end + + def bar + end + + def baz + eval(@foo) + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected b/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected new file mode 100644 index 0000000..716cf55 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected @@ -0,0 +1,69 @@ +edges +| impl/unsafeCode.rb:2:12:2:17 | target | impl/unsafeCode.rb:3:17:3:25 | #{...} | +| impl/unsafeCode.rb:7:12:7:12 | x | impl/unsafeCode.rb:8:30:8:30 | x | +| impl/unsafeCode.rb:12:12:12:12 | x | impl/unsafeCode.rb:13:33:13:33 | x | +| impl/unsafeCode.rb:28:17:28:22 | my_arr | impl/unsafeCode.rb:29:10:29:15 | my_arr | +| impl/unsafeCode.rb:32:21:32:21 | x | impl/unsafeCode.rb:33:12:33:12 | x | +| impl/unsafeCode.rb:33:5:33:7 | arr [element 0] | impl/unsafeCode.rb:34:10:34:12 | arr | +| impl/unsafeCode.rb:33:12:33:12 | x | impl/unsafeCode.rb:33:5:33:7 | arr [element 0] | +| impl/unsafeCode.rb:37:15:37:15 | x | impl/unsafeCode.rb:39:14:39:14 | x | +| impl/unsafeCode.rb:39:5:39:7 | [post] arr [element] | impl/unsafeCode.rb:40:10:40:12 | arr | +| impl/unsafeCode.rb:39:5:39:7 | [post] arr [element] | impl/unsafeCode.rb:44:10:44:12 | arr | +| impl/unsafeCode.rb:39:14:39:14 | x | impl/unsafeCode.rb:39:5:39:7 | [post] arr [element] | +| impl/unsafeCode.rb:47:15:47:15 | x | impl/unsafeCode.rb:49:9:49:12 | #{...} | +| impl/unsafeCode.rb:54:21:54:21 | x | impl/unsafeCode.rb:55:22:55:22 | x | +| impl/unsafeCode.rb:59:21:59:21 | x | impl/unsafeCode.rb:60:17:60:17 | x | +| impl/unsafeCode.rb:59:24:59:24 | y | impl/unsafeCode.rb:63:30:63:30 | y | +| impl/unsafeCode.rb:60:5:60:7 | arr [element 0] | impl/unsafeCode.rb:61:10:61:12 | arr | +| impl/unsafeCode.rb:60:11:60:18 | call to Array [element 0] | impl/unsafeCode.rb:60:5:60:7 | arr [element 0] | +| impl/unsafeCode.rb:60:17:60:17 | x | impl/unsafeCode.rb:60:11:60:18 | call to Array [element 0] | +| impl/unsafeCode.rb:63:5:63:8 | arr2 [element 0] | impl/unsafeCode.rb:64:10:64:13 | arr2 | +| impl/unsafeCode.rb:63:13:63:32 | call to Array [element 1] | impl/unsafeCode.rb:63:13:63:42 | call to join | +| impl/unsafeCode.rb:63:13:63:42 | call to join | impl/unsafeCode.rb:63:5:63:8 | arr2 [element 0] | +| impl/unsafeCode.rb:63:30:63:30 | y | impl/unsafeCode.rb:63:13:63:32 | call to Array [element 1] | +nodes +| impl/unsafeCode.rb:2:12:2:17 | target | semmle.label | target | +| impl/unsafeCode.rb:3:17:3:25 | #{...} | semmle.label | #{...} | +| impl/unsafeCode.rb:7:12:7:12 | x | semmle.label | x | +| impl/unsafeCode.rb:8:30:8:30 | x | semmle.label | x | +| impl/unsafeCode.rb:12:12:12:12 | x | semmle.label | x | +| impl/unsafeCode.rb:13:33:13:33 | x | semmle.label | x | +| impl/unsafeCode.rb:28:17:28:22 | my_arr | semmle.label | my_arr | +| impl/unsafeCode.rb:29:10:29:15 | my_arr | semmle.label | my_arr | +| impl/unsafeCode.rb:32:21:32:21 | x | semmle.label | x | +| impl/unsafeCode.rb:33:5:33:7 | arr [element 0] | semmle.label | arr [element 0] | +| impl/unsafeCode.rb:33:12:33:12 | x | semmle.label | x | +| impl/unsafeCode.rb:34:10:34:12 | arr | semmle.label | arr | +| impl/unsafeCode.rb:37:15:37:15 | x | semmle.label | x | +| impl/unsafeCode.rb:39:5:39:7 | [post] arr [element] | semmle.label | [post] arr [element] | +| impl/unsafeCode.rb:39:14:39:14 | x | semmle.label | x | +| impl/unsafeCode.rb:40:10:40:12 | arr | semmle.label | arr | +| impl/unsafeCode.rb:44:10:44:12 | arr | semmle.label | arr | +| impl/unsafeCode.rb:47:15:47:15 | x | semmle.label | x | +| impl/unsafeCode.rb:49:9:49:12 | #{...} | semmle.label | #{...} | +| impl/unsafeCode.rb:54:21:54:21 | x | semmle.label | x | +| impl/unsafeCode.rb:55:22:55:22 | x | semmle.label | x | +| impl/unsafeCode.rb:59:21:59:21 | x | semmle.label | x | +| impl/unsafeCode.rb:59:24:59:24 | y | semmle.label | y | +| impl/unsafeCode.rb:60:5:60:7 | arr [element 0] | semmle.label | arr [element 0] | +| impl/unsafeCode.rb:60:11:60:18 | call to Array [element 0] | semmle.label | call to Array [element 0] | +| impl/unsafeCode.rb:60:17:60:17 | x | semmle.label | x | +| impl/unsafeCode.rb:61:10:61:12 | arr | semmle.label | arr | +| impl/unsafeCode.rb:63:5:63:8 | arr2 [element 0] | semmle.label | arr2 [element 0] | +| impl/unsafeCode.rb:63:13:63:32 | call to Array [element 1] | semmle.label | call to Array [element 1] | +| impl/unsafeCode.rb:63:13:63:42 | call to join | semmle.label | call to join | +| impl/unsafeCode.rb:63:30:63:30 | y | semmle.label | y | +| impl/unsafeCode.rb:64:10:64:13 | arr2 | semmle.label | arr2 | +subpaths +#select +| impl/unsafeCode.rb:3:17:3:25 | #{...} | impl/unsafeCode.rb:2:12:2:17 | target | impl/unsafeCode.rb:3:17:3:25 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:2:12:2:17 | target | library input | impl/unsafeCode.rb:3:5:3:27 | call to eval | interpreted as code | +| impl/unsafeCode.rb:8:30:8:30 | x | impl/unsafeCode.rb:7:12:7:12 | x | impl/unsafeCode.rb:8:30:8:30 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:7:12:7:12 | x | library input | impl/unsafeCode.rb:8:5:8:32 | call to eval | interpreted as code | +| impl/unsafeCode.rb:13:33:13:33 | x | impl/unsafeCode.rb:12:12:12:12 | x | impl/unsafeCode.rb:13:33:13:33 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:12:12:12:12 | x | library input | impl/unsafeCode.rb:13:5:13:35 | call to eval | interpreted as code | +| impl/unsafeCode.rb:29:10:29:15 | my_arr | impl/unsafeCode.rb:28:17:28:22 | my_arr | impl/unsafeCode.rb:29:10:29:15 | my_arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:28:17:28:22 | my_arr | library input | impl/unsafeCode.rb:29:5:29:27 | call to eval | interpreted as code | +| impl/unsafeCode.rb:34:10:34:12 | arr | impl/unsafeCode.rb:32:21:32:21 | x | impl/unsafeCode.rb:34:10:34:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:32:21:32:21 | x | library input | impl/unsafeCode.rb:34:5:34:24 | call to eval | interpreted as code | +| impl/unsafeCode.rb:40:10:40:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x | impl/unsafeCode.rb:40:10:40:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:40:5:40:24 | call to eval | interpreted as code | +| impl/unsafeCode.rb:44:10:44:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x | impl/unsafeCode.rb:44:10:44:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:44:5:44:24 | call to eval | interpreted as code | +| impl/unsafeCode.rb:49:9:49:12 | #{...} | impl/unsafeCode.rb:47:15:47:15 | x | impl/unsafeCode.rb:49:9:49:12 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:47:15:47:15 | x | library input | impl/unsafeCode.rb:51:5:51:13 | call to eval | interpreted as code | +| impl/unsafeCode.rb:55:22:55:22 | x | impl/unsafeCode.rb:54:21:54:21 | x | impl/unsafeCode.rb:55:22:55:22 | x | This string concatenation which depends on $@ is later $@. | impl/unsafeCode.rb:54:21:54:21 | x | library input | impl/unsafeCode.rb:56:5:56:13 | call to eval | interpreted as code | +| impl/unsafeCode.rb:61:10:61:12 | arr | impl/unsafeCode.rb:59:21:59:21 | x | impl/unsafeCode.rb:61:10:61:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:59:21:59:21 | x | library input | impl/unsafeCode.rb:61:5:61:23 | call to eval | interpreted as code | +| impl/unsafeCode.rb:64:10:64:13 | arr2 | impl/unsafeCode.rb:59:24:59:24 | y | impl/unsafeCode.rb:64:10:64:13 | arr2 | This array which depends on $@ is later $@. | impl/unsafeCode.rb:59:24:59:24 | y | library input | impl/unsafeCode.rb:64:5:64:25 | call to eval | interpreted as code | diff --git a/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref b/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref new file mode 100644 index 0000000..ec33690 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref @@ -0,0 +1 @@ +queries/security/cwe-094/UnsafeCodeConstruction.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb new file mode 100644 index 0000000..df94549 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb @@ -0,0 +1,122 @@ +class Foobar + def foo1(target) +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval("foo = #{target}") # NOT OK + +# {/fact} + end + + # sprintf + def foo2(x) +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(sprintf("foo = %s", x)) # NOT OK + +# {/fact} + end + + # String#% + def foo3(x) +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval("foo = %{foo}" % {foo: x}) # NOT OK + +# {/fact} + end + + def indirect_eval(x) +# {fact rule=autoescape-disabled@v1.0 defects=0} + + eval(x) # OK - no construction. + +# {/fact} + end + + def send_stuff(x) +# {fact rule=autoescape-disabled@v1.0 defects=0} + + foo.send("foo_#{x}") # OK - attacker cannot control entire string. + +# {/fact} + end + + def named_code(code) +# {fact rule=autoescape-disabled@v1.0 defects=0} + + eval("def \n #{code} \n end") # OK - parameter is named code + +# {/fact} + end + + def joinStuff(my_arr) +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(my_arr.join("\n")) # NOT OK + +# {/fact} + end + + def joinWithElemt(x) + arr = [x, "foobar"] +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(arr.join("\n")) # NOT OK + +# {/fact} + end + + def pushArr(x, y) + arr = [] + arr.push(x) +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(arr.join("\n")) # NOT OK + +# {/fact} + + arr2 = [] + arr2 << y +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(arr.join("\n")) # NOT OK + +# {/fact} + end + + def hereDoc(x) + foo = <<~HERE + #{x} + HERE +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(foo) # NOT OK + +# {/fact} + end + + def string_concat(x) + foo = "foo = " + x +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(foo) # NOT OK + +# {/fact} + end + + def join_indirect(x, y) + arr = Array(x) +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(arr.join(" ")) # NOT OK + +# {/fact} + + arr2 = [Array(["foo = ", y]).join(" ")] +# {fact rule=autoescape-disabled@v1.0 defects=1} + + eval(arr2.join("\n")) # NOT OK + +# {/fact} + end +end diff --git a/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/unsafe-code.gemspec b/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/unsafe-code.gemspec new file mode 100644 index 0000000..ab9639a --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-094/UnsafeCodeConstruction/unsafe-code.gemspec @@ -0,0 +1,5 @@ +Gem::Specification.new do |s| + s.name = 'unsafe-code' + s.require_path = "impl" + end + \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/BadTagFilter.expected b/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/BadTagFilter.expected new file mode 100644 index 0000000..edd6347 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/BadTagFilter.expected @@ -0,0 +1,14 @@ +| test.rb:2:6:2:29 | .*?<\\/script> | This regular expression does not match script end tags like . | +| test.rb:3:6:3:29 | .*?<\\/script> | This regular expression does not match script end tags like . | +| test.rb:7:6:7:16 | )\|([^\\/\\s>]+)[\\S\\s]*?> | Comments ending with --> are matched differently from comments ending with --!>. The first is matched with capture group 1 and comments ending with --!> are matched with capture group 2. | +| test.rb:19:6:19:147 | <(?:(?:\\/([^>]+)>)\|(?:!--([\\S\|\\s]*?)-->)\|(?:([^\\/\\s>]+)((?:\\s+[\\w\\-:.]+(?:\\s*=\\s*?(?:(?:"[^"]*")\|(?:'[^']*')\|[^\\s"'\\/>]+))?)*)[\\S\\s]*?(\\/?)>)) | Comments ending with --> are matched differently from comments ending with --!>. The first is matched with capture group 2 and comments ending with --!> are matched with capture group 3, 4. | diff --git a/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/BadTagFilter.qlref b/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/BadTagFilter.qlref new file mode 100644 index 0000000..6780ef6 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/BadTagFilter.qlref @@ -0,0 +1 @@ +queries/security/cwe-116/BadTagFilter.ql \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/case.rb b/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/case.rb new file mode 100644 index 0000000..6abb38c --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-116/BadTagFilter/case.rb @@ -0,0 +1,94 @@ +filters = [ +# {fact rule=autoescape-disabled@v1.0 defects=1} + + /.*?<\/script>/i, # NOT OK - doesn't match newlines or `` + +# {/fact} +# {fact rule=autoescape-disabled@v1.0 defects=1} + + /.*?<\/script>/im, # NOT OK - doesn't match `` + +# {/fact} +# {fact rule=autoescape-disabled@v1.0 defects=0} + + /.*?<\/script[^>]*>/im, # OK + +# {/fact} +# {fact rule=autoescape-disabled@v1.0 defects=0} + + //im, # OK - we don't care regexps that only match comments + +# {/fact} +# {fact rule=autoescape-disabled@v1.0 defects=0} + + /)|([^\/\s>]+)[\S\s]*?>/, # NOT OK - doesn't match comments with the right capture groups + +# {/fact} +# {fact rule=autoescape-disabled@v1.0 defects=1} + + /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/, # NOT OK - capture groups + +# {/fact} +] + +doFilters(filters) \ No newline at end of file diff --git a/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/IncompleteMultiCharacterSanitization.expected b/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/IncompleteMultiCharacterSanitization.expected new file mode 100644 index 0000000..48de917 --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/IncompleteMultiCharacterSanitization.expected @@ -0,0 +1,2 @@ +failures +testFailures diff --git a/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/IncompleteMultiCharacterSanitization.ql b/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/IncompleteMultiCharacterSanitization.ql new file mode 100644 index 0000000..b9b447f --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/IncompleteMultiCharacterSanitization.ql @@ -0,0 +1,39 @@ +/** + * @kind problem + */ + +import codeql.ruby.AST +import codeql.ruby.regexp.RegExpTreeView as RETV +import codeql.ruby.DataFlow +import codeql.ruby.security.IncompleteMultiCharacterSanitizationQuery as Query +import TestUtilities.InlineExpectationsTest + +module Test implements TestSig { + string getARelevantTag() { result = "hasResult" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasResult" and + hasResult(location, element, value) + } +} + +import MakeTest + +predicate hasResult(Location location, string element, string value) { + exists(DataFlow::Node replace, string kind | + replace.getLocation() = location and + element = replace.toString() and + value = shortKind(kind) + | + Query::isResult(replace, _, _, kind) + ) +} + +bindingset[kind] +string shortKind(string kind) { + kind = "an HTML element injection vulnerability" and result = "html" + or + kind = "a path injection vulnerability" and result = "path" + or + kind = "an HTML attribute injection vulnerability" and result = "attr" +} diff --git a/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/incomplete_multi_character_sanitization.rb b/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/incomplete_multi_character_sanitization.rb new file mode 100644 index 0000000..df66e8b --- /dev/null +++ b/PR_10_ruby/codeql_ruby/cwe-116/IncompleteMultiCharacterSanitization/incomplete_multi_character_sanitization.rb @@ -0,0 +1,221 @@ +# CVE-2019-10756 +def m1(content) + content = content.gsub(/<.*cript.*\/scrip.*>/i, "") # $ hasResult=html + content = content.gsub(/ on\w+=".*"/, "") # $ hasResult=attr + content = content.gsub(/ on\w+=\'.*\'/, "") # $ hasResult=attr + content +end + +def m2(content) + content = content.gsub(/<.*cript.*/i, "") # $ hasResult=html + content = content.gsub(/.on\w+=.*".*"/, "") # $ hasResult=attr + content = content.gsub(/.on\w+=.*\'.*\'/, "") # $ hasResult=attr + + content +end + +# CVE-2020-7656 +def m3(text) + rscript = /)<[^<]*)*<\/script>/i + text.gsub(rscript, "") # $ hasResult=html + text +end + +# CVE-2019-1010091 +def m4(text) + text.gsub(//m, "") # $ hasResult=html + x = x.gsub(/\sng-[a-z-]+/, "") # $ hasResult=attr + x = x.gsub(/\sng-[a-z-]+/, "") # $ hasResult=attr + +# {fact rule=autoescape-disabled@v1.0 defects=0} + + x = x.gsub(/()/, "\n") # OK: not a sanitizer + +# {/fact} + + x = x.gsub(//, "") # $ SPURIOUS: hasResult=html SPURIOUS: hasResult=attr +# {fact rule=autoescape-disabled@v1.0 defects=0} + + x = x.gsub(/