safe_yaml-instructure 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +45 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +124 -0
- data/Rakefile +6 -0
- data/lib/safe_yaml.rb +145 -0
- data/lib/safe_yaml/psych_tag_verifier.rb +38 -0
- data/lib/safe_yaml/syck_tag_verifier.rb +27 -0
- data/lib/safe_yaml/tag_verifier.rb +23 -0
- data/lib/safe_yaml/version.rb +3 -0
- data/lib/safe_yaml/whitelist.rb +74 -0
- data/run_specs_all_ruby_versions.sh +21 -0
- data/safe_yaml.gemspec +24 -0
- data/spec/exploit.1.9.2.yaml +2 -0
- data/spec/exploit.1.9.3.yaml +2 -0
- data/spec/ok.yaml +3 -0
- data/spec/safe_yaml_spec.rb +541 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/exploitable_back_door.rb +29 -0
- data/spec/whitelist_spec.rb +46 -0
- data/spec/yaml_load_spec.rb +150 -0
- metadata +166 -0
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
HERE = File.dirname(__FILE__) unless defined?(HERE)
|
2
|
+
ROOT = File.join(HERE, "..") unless defined?(ROOT)
|
3
|
+
|
4
|
+
$LOAD_PATH << File.join(ROOT, "lib")
|
5
|
+
$LOAD_PATH << File.join(HERE, "support")
|
6
|
+
|
7
|
+
if ENV["YAMLER"] && defined?(YAML::ENGINE)
|
8
|
+
require "yaml"
|
9
|
+
YAML::ENGINE.yamler = ENV["YAMLER"]
|
10
|
+
puts "Running specs in Ruby #{RUBY_VERSION} with '#{YAML::ENGINE.yamler}' YAML engine."
|
11
|
+
end
|
12
|
+
|
13
|
+
require "safe_yaml"
|
14
|
+
require "hashie"
|
15
|
+
require "heredoc_unindent"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class ExploitableBackDoor
|
2
|
+
def exploited?
|
3
|
+
@exploited_through_setter || @exploited_through_init_with || @exploited_through_ivars
|
4
|
+
end
|
5
|
+
|
6
|
+
def exploited_through_setter?
|
7
|
+
@exploited_through_setter
|
8
|
+
end
|
9
|
+
|
10
|
+
def exploited_through_init_with?
|
11
|
+
@exploited_through_init_with
|
12
|
+
end
|
13
|
+
|
14
|
+
def exploited_through_ivars?
|
15
|
+
self.instance_variables.any?
|
16
|
+
end
|
17
|
+
|
18
|
+
def init_with(command)
|
19
|
+
# Note: this is how bad this COULD be.
|
20
|
+
# system("#{command}")
|
21
|
+
@exploited_through_init_with = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def []=(command, arguments)
|
25
|
+
# Note: this is how bad this COULD be.
|
26
|
+
# system("#{command} #{arguments}")
|
27
|
+
@exploited_through_setter = true
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe SafeYAML::Whitelist do
|
4
|
+
let(:whitelist) { SafeYAML::Whitelist.new }
|
5
|
+
|
6
|
+
it "should start with the default whitelist" do
|
7
|
+
whitelist.allowed.size.should > 0
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should allow inserting and deleting tags" do
|
11
|
+
whitelist.check('test1', nil).should == nil
|
12
|
+
whitelist.add('test1')
|
13
|
+
whitelist.check('test1', nil).should == :cacheable
|
14
|
+
whitelist.remove('test1')
|
15
|
+
whitelist.check('test1', nil).should == nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should allow using a block" do
|
19
|
+
whitelist.add('test1') { |val| val == 'ok' }
|
20
|
+
whitelist.check('test1', 'bad').should == nil
|
21
|
+
whitelist.check('test1', 'ok').should == :allowed
|
22
|
+
whitelist.check('test1', 'bad').should == nil
|
23
|
+
whitelist.remove('test1')
|
24
|
+
whitelist.check('test1', 'ok').should == nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it "overwrites on second add" do
|
28
|
+
whitelist.add('test1') { |val| val == 'ok' }
|
29
|
+
whitelist.add('test1') { |val| val == 'second' }
|
30
|
+
whitelist.check('test1', 'ok').should == nil
|
31
|
+
whitelist.check('test1', 'second').should == :allowed
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow caching the block response" do
|
35
|
+
counter = 0
|
36
|
+
whitelist.add('test1') { |val| val == 'ok' && (counter += 1) && :cacheable }
|
37
|
+
whitelist.check('test1', 'bad').should == nil
|
38
|
+
whitelist.check('test1', 'ok').should == :cacheable
|
39
|
+
whitelist.check('test1', 'bad').should == nil
|
40
|
+
whitelist.check('test1', 'ok').should == :cacheable
|
41
|
+
whitelist.check('test1', 'ok').should == :cacheable
|
42
|
+
counter.should == 1
|
43
|
+
whitelist.remove('test1')
|
44
|
+
whitelist.check('test1', 'ok').should == nil
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe "safe_load" do
|
4
|
+
let(:result) { @result }
|
5
|
+
def parse(yaml)
|
6
|
+
@result = YAML.load(yaml.unindent)
|
7
|
+
end
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
YAML.disable_symbol_parsing!
|
11
|
+
SafeYAML::OPTIONS[:suppress_warnings] = true
|
12
|
+
end
|
13
|
+
|
14
|
+
context "by default" do
|
15
|
+
it "translates maps to hashes" do
|
16
|
+
parse <<-YAML
|
17
|
+
potayto: potahto
|
18
|
+
tomayto: tomahto
|
19
|
+
YAML
|
20
|
+
|
21
|
+
result.should == {
|
22
|
+
"potayto" => "potahto",
|
23
|
+
"tomayto" => "tomahto"
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "translates sequences to arrays" do
|
28
|
+
parse <<-YAML
|
29
|
+
- foo
|
30
|
+
- bar
|
31
|
+
- baz
|
32
|
+
YAML
|
33
|
+
|
34
|
+
result.should == ["foo", "bar", "baz"]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "translates most values to strings" do
|
38
|
+
parse "string: value"
|
39
|
+
result.should == { "string" => "value" }
|
40
|
+
end
|
41
|
+
|
42
|
+
it "does not deserialize symbols" do
|
43
|
+
expect { parse ":symbol: value" }.to raise_error(SafeYAML::UnsafeTagError)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "translates valid integral numbers to integers" do
|
47
|
+
parse "integer: 1"
|
48
|
+
result.should == { "integer" => 1 }
|
49
|
+
end
|
50
|
+
|
51
|
+
it "translates valid decimal numbers to floats" do
|
52
|
+
parse "float: 3.14"
|
53
|
+
result.should == { "float" => 3.14 }
|
54
|
+
end
|
55
|
+
|
56
|
+
it "translates valid dates" do
|
57
|
+
parse "date: 2013-01-24"
|
58
|
+
result.should == { "date" => Date.parse("2013-01-24") }
|
59
|
+
end
|
60
|
+
|
61
|
+
it "translates valid true/false values to booleans" do
|
62
|
+
parse <<-YAML
|
63
|
+
- yes
|
64
|
+
- true
|
65
|
+
- no
|
66
|
+
- false
|
67
|
+
YAML
|
68
|
+
|
69
|
+
result.should == [true, true, false, false]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "translates valid nulls to nil" do
|
73
|
+
parse <<-YAML
|
74
|
+
-
|
75
|
+
- ~
|
76
|
+
- null
|
77
|
+
YAML
|
78
|
+
|
79
|
+
result.should == [nil] * 3
|
80
|
+
end
|
81
|
+
|
82
|
+
it "translates quoted empty strings to strings (not nil)" do
|
83
|
+
parse "foo: ''"
|
84
|
+
result.should == { "foo" => "" }
|
85
|
+
end
|
86
|
+
|
87
|
+
it "correctly reverse-translates strings encoded via #to_yaml" do
|
88
|
+
parse "5.10".to_yaml
|
89
|
+
result.should == "5.10"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "does not treat quoted strings as symbols" do
|
93
|
+
parse <<-YAML
|
94
|
+
- ":abcd"
|
95
|
+
- ':abcd'
|
96
|
+
YAML
|
97
|
+
|
98
|
+
result.should == [":abcd", ":abcd"]
|
99
|
+
end
|
100
|
+
|
101
|
+
it "deals just fine with nested maps" do
|
102
|
+
parse <<-YAML
|
103
|
+
foo:
|
104
|
+
bar:
|
105
|
+
marco: polo
|
106
|
+
YAML
|
107
|
+
|
108
|
+
result.should == { "foo" => { "bar" => { "marco" => "polo" } } }
|
109
|
+
end
|
110
|
+
|
111
|
+
it "deals just fine with nested sequences" do
|
112
|
+
parse <<-YAML
|
113
|
+
- foo
|
114
|
+
-
|
115
|
+
- bar1
|
116
|
+
- bar2
|
117
|
+
-
|
118
|
+
- baz1
|
119
|
+
- baz2
|
120
|
+
YAML
|
121
|
+
|
122
|
+
result.should == ["foo", ["bar1", "bar2", ["baz1", "baz2"]]]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "with symbol parsing enabled" do
|
127
|
+
before :each do
|
128
|
+
YAML.enable_symbol_parsing!
|
129
|
+
end
|
130
|
+
|
131
|
+
after :each do
|
132
|
+
YAML.disable_symbol_parsing!
|
133
|
+
end
|
134
|
+
|
135
|
+
it "translates values starting with ':' to symbols" do
|
136
|
+
parse "symbol: :value"
|
137
|
+
result.should == { "symbol" => :value }
|
138
|
+
end
|
139
|
+
|
140
|
+
it "applies the same transformation to keys" do
|
141
|
+
parse ":bar: symbol"
|
142
|
+
result.should == { :bar => "symbol" }
|
143
|
+
end
|
144
|
+
|
145
|
+
it "applies the same transformation to elements in sequences" do
|
146
|
+
parse "- :bar"
|
147
|
+
result.should == [:bar]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: safe_yaml-instructure
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 63
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 8
|
9
|
+
- 0
|
10
|
+
version: 0.8.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dan Tao
|
14
|
+
- Brian Palmer
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2013-02-15 00:00:00 Z
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: hashie
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: heredoc_unindent
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rake
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rspec
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: travis-lint
|
79
|
+
prerelease: false
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
type: :development
|
90
|
+
version_requirements: *id005
|
91
|
+
description: Parse YAML safely, without that pesky arbitrary object deserialization vulnerability
|
92
|
+
email: brianp@instructure.com
|
93
|
+
executables: []
|
94
|
+
|
95
|
+
extensions: []
|
96
|
+
|
97
|
+
extra_rdoc_files: []
|
98
|
+
|
99
|
+
files:
|
100
|
+
- .gitignore
|
101
|
+
- .travis.yml
|
102
|
+
- Gemfile
|
103
|
+
- LICENSE.txt
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- lib/safe_yaml.rb
|
107
|
+
- lib/safe_yaml/psych_tag_verifier.rb
|
108
|
+
- lib/safe_yaml/syck_tag_verifier.rb
|
109
|
+
- lib/safe_yaml/tag_verifier.rb
|
110
|
+
- lib/safe_yaml/version.rb
|
111
|
+
- lib/safe_yaml/whitelist.rb
|
112
|
+
- run_specs_all_ruby_versions.sh
|
113
|
+
- safe_yaml.gemspec
|
114
|
+
- spec/exploit.1.9.2.yaml
|
115
|
+
- spec/exploit.1.9.3.yaml
|
116
|
+
- spec/ok.yaml
|
117
|
+
- spec/safe_yaml_spec.rb
|
118
|
+
- spec/spec_helper.rb
|
119
|
+
- spec/support/exploitable_back_door.rb
|
120
|
+
- spec/whitelist_spec.rb
|
121
|
+
- spec/yaml_load_spec.rb
|
122
|
+
homepage: http://github.com/instructure/safe_yaml/
|
123
|
+
licenses:
|
124
|
+
- MIT
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
|
128
|
+
require_paths:
|
129
|
+
- lib
|
130
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
hash: 57
|
136
|
+
segments:
|
137
|
+
- 1
|
138
|
+
- 8
|
139
|
+
- 7
|
140
|
+
version: 1.8.7
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
none: false
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
hash: 3
|
147
|
+
segments:
|
148
|
+
- 0
|
149
|
+
version: "0"
|
150
|
+
requirements: []
|
151
|
+
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 1.8.15
|
154
|
+
signing_key:
|
155
|
+
specification_version: 3
|
156
|
+
summary: SameYAML provides an alternative implementation of YAML.load suitable for accepting user input in Ruby applications.
|
157
|
+
test_files:
|
158
|
+
- spec/exploit.1.9.2.yaml
|
159
|
+
- spec/exploit.1.9.3.yaml
|
160
|
+
- spec/ok.yaml
|
161
|
+
- spec/safe_yaml_spec.rb
|
162
|
+
- spec/spec_helper.rb
|
163
|
+
- spec/support/exploitable_back_door.rb
|
164
|
+
- spec/whitelist_spec.rb
|
165
|
+
- spec/yaml_load_spec.rb
|
166
|
+
has_rdoc:
|