safe_yaml-instructure 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|