Skip to content

Commit 2edbc16

Browse files
committed
Ruby: add Hash.from_trusted_xml as an unsafe deserialization sink
1 parent 8689539 commit 2edbc16

File tree

4 files changed

+27
-0
lines changed

4 files changed

+27
-0
lines changed

ruby/ql/lib/codeql/ruby/security/UnsafeDeserializationCustomizations.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ module UnsafeDeserialization {
6767
}
6868
}
6969

70+
/**
71+
* The first argument in a call to `Hash.from_trusted_xml`, considered as a
72+
* sink for unsafe deserialization.
73+
*/
74+
class HashFromTrustedXmlArgument extends Sink {
75+
HashFromTrustedXmlArgument() {
76+
this = API::getTopLevelMember("Hash").getAMethodCall("from_trusted_xml").getArgument(0)
77+
}
78+
}
79+
7080
private string getAKnownOjModeName(boolean isSafe) {
7181
result = ["compat", "custom", "json", "null", "rails", "strict", "wab"] and isSafe = true
7282
or
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The `rb/unsafe-deserialization` query now includes alerts for user-controlled data passed to `Hash.from_trusted_xml`, since that method can deserialize YAML embedded in the XML, which in turn can result in deserialization of arbitrary objects.

ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ edges
1414
| UnsafeDeserialization.rb:51:17:51:28 | ...[...] : | UnsafeDeserialization.rb:53:22:53:30 | json_data |
1515
| UnsafeDeserialization.rb:58:17:58:22 | call to params : | UnsafeDeserialization.rb:58:17:58:28 | ...[...] : |
1616
| UnsafeDeserialization.rb:58:17:58:28 | ...[...] : | UnsafeDeserialization.rb:68:23:68:31 | json_data |
17+
| UnsafeDeserialization.rb:80:11:80:16 | call to params : | UnsafeDeserialization.rb:80:11:80:22 | ...[...] : |
18+
| UnsafeDeserialization.rb:80:11:80:22 | ...[...] : | UnsafeDeserialization.rb:81:34:81:36 | xml |
1719
nodes
1820
| UnsafeDeserialization.rb:9:39:9:44 | call to params : | semmle.label | call to params : |
1921
| UnsafeDeserialization.rb:9:39:9:50 | ...[...] : | semmle.label | ...[...] : |
@@ -37,6 +39,9 @@ nodes
3739
| UnsafeDeserialization.rb:58:17:58:22 | call to params : | semmle.label | call to params : |
3840
| UnsafeDeserialization.rb:58:17:58:28 | ...[...] : | semmle.label | ...[...] : |
3941
| UnsafeDeserialization.rb:68:23:68:31 | json_data | semmle.label | json_data |
42+
| UnsafeDeserialization.rb:80:11:80:16 | call to params : | semmle.label | call to params : |
43+
| UnsafeDeserialization.rb:80:11:80:22 | ...[...] : | semmle.label | ...[...] : |
44+
| UnsafeDeserialization.rb:81:34:81:36 | xml | semmle.label | xml |
4045
subpaths
4146
#select
4247
| UnsafeDeserialization.rb:10:27:10:41 | serialized_data | UnsafeDeserialization.rb:9:39:9:44 | call to params : | UnsafeDeserialization.rb:10:27:10:41 | serialized_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:9:39:9:44 | call to params | user-provided value |
@@ -47,3 +52,4 @@ subpaths
4752
| UnsafeDeserialization.rb:52:22:52:30 | json_data | UnsafeDeserialization.rb:51:17:51:22 | call to params : | UnsafeDeserialization.rb:52:22:52:30 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:51:17:51:22 | call to params | user-provided value |
4853
| UnsafeDeserialization.rb:53:22:53:30 | json_data | UnsafeDeserialization.rb:51:17:51:22 | call to params : | UnsafeDeserialization.rb:53:22:53:30 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:51:17:51:22 | call to params | user-provided value |
4954
| UnsafeDeserialization.rb:68:23:68:31 | json_data | UnsafeDeserialization.rb:58:17:58:22 | call to params : | UnsafeDeserialization.rb:68:23:68:31 | json_data | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:58:17:58:22 | call to params | user-provided value |
55+
| UnsafeDeserialization.rb:81:34:81:36 | xml | UnsafeDeserialization.rb:80:11:80:16 | call to params : | UnsafeDeserialization.rb:81:34:81:36 | xml | Unsafe deserialization depends on a $@. | UnsafeDeserialization.rb:80:11:80:16 | call to params | user-provided value |

ruby/ql/test/query-tests/security/cwe-502/unsafe-deserialization/UnsafeDeserialization.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,11 @@ def route9
7373
json_data = params[:key]
7474
object = Oj.safe_load json_data
7575
end
76+
77+
# BAD - `Hash.from_trusted_xml` will deserialize elements with the
78+
# `type="yaml"` attribute as YAML.
79+
def route10
80+
xml = params[:key]
81+
hash = Hash.from_trusted_xml(xml)
82+
end
7683
end

0 commit comments

Comments
 (0)