safe_yaml 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/CHANGES.md +19 -0
- data/lib/safe_yaml.rb +6 -8
- data/lib/safe_yaml/load.rb +48 -25
- data/lib/safe_yaml/parse/date.rb +1 -1
- data/lib/safe_yaml/version.rb +1 -1
- data/spec/psych_resolver_spec.rb +1 -1
- data/spec/resolver_specs.rb +25 -2
- data/spec/safe_yaml_spec.rb +42 -1
- data/spec/spec_helper.rb +11 -4
- data/spec/syck_resolver_spec.rb +1 -1
- data/spec/transform/base64_spec.rb +1 -1
- data/spec/transform/to_date_spec.rb +2 -2
- data/spec/transform/to_float_spec.rb +1 -1
- data/spec/transform/to_integer_spec.rb +1 -1
- data/spec/transform/to_symbol_spec.rb +1 -1
- data/spec/yaml_spec.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6cf9f3e405ec65c54f30eaec331423a67877dc34
|
4
|
+
data.tar.gz: 0cf7116a88485be0057ff010ab330569391a9e2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63cb08bcc97ac6e4bf25e1da93f047f0edf1726ea404864e7e47fc920dd3c8f8df988b7e532efbb31ef6d611c24cf43577978eee12817e273e8ea254b2f55203
|
7
|
+
data.tar.gz: 89be3d3d4be1c8f9dc54f7d41842a443b6d8fe71586c7d79a3002fc87a71db83809d59679f431221877fdd2fc8da3a0e88ed7b79a534b1d0cc75d2218c12f4c6
|
data/.gitignore
CHANGED
data/CHANGES.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
1.0.2
|
2
|
+
-----
|
3
|
+
|
4
|
+
- added warning when using Psych + an older version of libyaml
|
5
|
+
|
6
|
+
1.0.1
|
7
|
+
-----
|
8
|
+
|
9
|
+
- fixed handling for strings that look like (invalid) dates
|
10
|
+
|
11
|
+
1.0.0
|
12
|
+
-----
|
13
|
+
|
14
|
+
- updated date parsing to use local timezone
|
15
|
+
- **now requiring "safe_yaml/load" provides `SafeYAML.load` without clobbering `YAML`**
|
16
|
+
- fixed handling of empty files
|
17
|
+
- fixed some (edge case) integer parsing bugs
|
18
|
+
- fixed some JRuby-specific issues
|
19
|
+
|
1
20
|
0.9.7
|
2
21
|
-----
|
3
22
|
|
data/lib/safe_yaml.rb
CHANGED
@@ -33,21 +33,19 @@ module YAML
|
|
33
33
|
SafeYAML.load_file(*args)
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
if SafeYAML::MULTI_ARGUMENT_YAML_LOAD
|
37
|
+
def self.unsafe_load_file(filename)
|
38
38
|
# https://github.com/tenderlove/psych/blob/v1.3.2/lib/psych.rb#L296-298
|
39
39
|
File.open(filename, 'r:bom|utf-8') { |f| self.unsafe_load(f, filename) }
|
40
|
-
|
40
|
+
end
|
41
|
+
|
42
|
+
else
|
43
|
+
def self.unsafe_load_file(filename)
|
41
44
|
# https://github.com/tenderlove/psych/blob/v1.2.2/lib/psych.rb#L231-233
|
42
45
|
self.unsafe_load File.open(filename)
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
46
|
-
def self.unsafe_load_file(filename)
|
47
|
-
# https://github.com/indeyets/syck/blob/master/ext/ruby/lib/yaml.rb#L133-135
|
48
|
-
File.open(filename) { |f| self.unsafe_load(f) }
|
49
|
-
end
|
50
|
-
|
51
49
|
class << self
|
52
50
|
alias_method :unsafe_load, :load
|
53
51
|
alias_method :load, :load_with_options
|
data/lib/safe_yaml/load.rb
CHANGED
@@ -4,8 +4,34 @@ require "yaml"
|
|
4
4
|
# their behavior off of this.
|
5
5
|
module SafeYAML
|
6
6
|
YAML_ENGINE = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : "syck"
|
7
|
+
LIBYAML_VERSION = YAML_ENGINE == "psych" && Psych.const_defined?("LIBYAML_VERSION", false) ? Psych::LIBYAML_VERSION : nil
|
8
|
+
|
9
|
+
def self.check_libyaml_version
|
10
|
+
if YAML_ENGINE == "psych" && (LIBYAML_VERSION.nil? || LIBYAML_VERSION < "0.1.6")
|
11
|
+
Kernel.warn <<-EOWARNING.gsub(/^ +/, ' ')
|
12
|
+
|
13
|
+
\e[33mSafeYAML Warning\e[39m
|
14
|
+
\e[33m----------------\e[39m
|
15
|
+
|
16
|
+
\e[31mYou appear to have an outdated version of libyaml (#{LIBYAML_VERSION}) installed on your system.\e[39m
|
17
|
+
|
18
|
+
Prior to 0.1.6, libyaml is vulnerable to a heap overflow exploit from malicious YAML payloads.
|
19
|
+
|
20
|
+
For more info, see:
|
21
|
+
https://www.ruby-lang.org/en/news/2014/03/29/heap-overflow-in-yaml-uri-escape-parsing-cve-2014-2525/
|
22
|
+
|
23
|
+
The easiest thing to do right now is probably to update Psych to the latest version and enable
|
24
|
+
the 'bundled-libyaml' option, which will install a vendored libyaml with the vulnerability patched:
|
25
|
+
|
26
|
+
\e[32mgem install psych -- --enable-bundled-libyaml\e[39m
|
27
|
+
|
28
|
+
EOWARNING
|
29
|
+
end
|
30
|
+
end
|
7
31
|
end
|
8
32
|
|
33
|
+
SafeYAML.check_libyaml_version
|
34
|
+
|
9
35
|
require "set"
|
10
36
|
require "safe_yaml/deep"
|
11
37
|
require "safe_yaml/parse/hexadecimal"
|
@@ -36,7 +62,28 @@ module SafeYAML
|
|
36
62
|
|
37
63
|
OPTIONS = Deep.copy(DEFAULT_OPTIONS)
|
38
64
|
|
65
|
+
PREDEFINED_TAGS = {}
|
66
|
+
|
67
|
+
if YAML_ENGINE == "syck"
|
68
|
+
YAML.tagged_classes.each do |tag, klass|
|
69
|
+
PREDEFINED_TAGS[klass] = tag
|
70
|
+
end
|
71
|
+
|
72
|
+
else
|
73
|
+
# Special tags appear to be hard-coded in Psych:
|
74
|
+
# https://github.com/tenderlove/psych/blob/v1.3.4/lib/psych/visitors/to_ruby.rb
|
75
|
+
# Fortunately, there aren't many that SafeYAML doesn't already support.
|
76
|
+
PREDEFINED_TAGS.merge!({
|
77
|
+
Exception => "!ruby/exception",
|
78
|
+
Range => "!ruby/range",
|
79
|
+
Regexp => "!ruby/regexp",
|
80
|
+
})
|
81
|
+
end
|
82
|
+
|
83
|
+
Deep.freeze(PREDEFINED_TAGS)
|
84
|
+
|
39
85
|
module_function
|
86
|
+
|
40
87
|
def restore_defaults!
|
41
88
|
OPTIONS.clear.merge!(Deep.copy(DEFAULT_OPTIONS))
|
42
89
|
end
|
@@ -61,7 +108,7 @@ module SafeYAML
|
|
61
108
|
raise "#{klass} cannot be anonymous" if klass_name.nil? || klass_name.empty?
|
62
109
|
|
63
110
|
# Whitelist any built-in YAML tags supplied by Syck or Psych.
|
64
|
-
predefined_tag =
|
111
|
+
predefined_tag = PREDEFINED_TAGS[klass]
|
65
112
|
if predefined_tag
|
66
113
|
OPTIONS[:whitelisted_tags] << predefined_tag
|
67
114
|
return
|
@@ -78,30 +125,6 @@ module SafeYAML
|
|
78
125
|
OPTIONS[:whitelisted_tags] << "#{tag_prefix}:#{klass_name}"
|
79
126
|
end
|
80
127
|
|
81
|
-
def predefined_tags
|
82
|
-
if @predefined_tags.nil?
|
83
|
-
@predefined_tags = {}
|
84
|
-
|
85
|
-
if YAML_ENGINE == "syck"
|
86
|
-
YAML.tagged_classes.each do |tag, klass|
|
87
|
-
@predefined_tags[klass] = tag
|
88
|
-
end
|
89
|
-
|
90
|
-
else
|
91
|
-
# Special tags appear to be hard-coded in Psych:
|
92
|
-
# https://github.com/tenderlove/psych/blob/v1.3.4/lib/psych/visitors/to_ruby.rb
|
93
|
-
# Fortunately, there aren't many that SafeYAML doesn't already support.
|
94
|
-
@predefined_tags.merge!({
|
95
|
-
Exception => "!ruby/exception",
|
96
|
-
Range => "!ruby/range",
|
97
|
-
Regexp => "!ruby/regexp",
|
98
|
-
})
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
@predefined_tags
|
103
|
-
end
|
104
|
-
|
105
128
|
if YAML_ENGINE == "psych"
|
106
129
|
def tag_is_explicitly_trusted?(tag)
|
107
130
|
false
|
data/lib/safe_yaml/parse/date.rb
CHANGED
@@ -19,7 +19,7 @@ module SafeYAML
|
|
19
19
|
|
20
20
|
# The DateTime class has a #to_time method in Ruby 1.9+;
|
21
21
|
# Before that we'll just need to convert DateTime to Time ourselves.
|
22
|
-
TO_TIME_AVAILABLE = DateTime.
|
22
|
+
TO_TIME_AVAILABLE = DateTime.instance_methods.include?(:to_time)
|
23
23
|
|
24
24
|
def self.value(value)
|
25
25
|
d = DateTime.parse(value)
|
data/lib/safe_yaml/version.rb
CHANGED
data/spec/psych_resolver_spec.rb
CHANGED
data/spec/resolver_specs.rb
CHANGED
@@ -16,8 +16,31 @@ module ResolverSpecs
|
|
16
16
|
|
17
17
|
# Isn't this how I should've been doing it all along?
|
18
18
|
def parse_and_test(yaml)
|
19
|
-
parse(yaml)
|
20
|
-
|
19
|
+
safe_result = parse(yaml)
|
20
|
+
|
21
|
+
exception_thrown = nil
|
22
|
+
|
23
|
+
unsafe_result = begin
|
24
|
+
YAML.unsafe_load(yaml)
|
25
|
+
rescue Exception => e
|
26
|
+
exception_thrown = e
|
27
|
+
end
|
28
|
+
|
29
|
+
if exception_thrown
|
30
|
+
# If the underlying YAML parser (e.g. Psych) threw an exception, I'm
|
31
|
+
# honestly not sure what the right thing to do is. For now I'll just
|
32
|
+
# print a warning. Should SafeYAML fail when Psych fails?
|
33
|
+
Kernel.warn "\n"
|
34
|
+
Kernel.warn "Discrepancy between SafeYAML and #{SafeYAML::YAML_ENGINE} on input:\n"
|
35
|
+
Kernel.warn "#{yaml.unindent}\n"
|
36
|
+
Kernel.warn "SafeYAML result:"
|
37
|
+
Kernel.warn "#{safe_result.inspect}\n"
|
38
|
+
Kernel.warn "#{SafeYAML::YAML_ENGINE} result:"
|
39
|
+
Kernel.warn "#{exception_thrown.inspect}\n"
|
40
|
+
|
41
|
+
else
|
42
|
+
safe_result.should == unsafe_result
|
43
|
+
end
|
21
44
|
end
|
22
45
|
|
23
46
|
context "by default" do
|
data/spec/safe_yaml_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe YAML do
|
4
4
|
# Essentially stolen from:
|
@@ -32,6 +32,47 @@ describe YAML do
|
|
32
32
|
SafeYAML.restore_defaults!
|
33
33
|
end
|
34
34
|
|
35
|
+
describe "check_libyaml_version" do
|
36
|
+
REAL_YAML_ENGINE = SafeYAML::YAML_ENGINE
|
37
|
+
REAL_LIBYAML_VERSION = SafeYAML::LIBYAML_VERSION
|
38
|
+
|
39
|
+
after :each do
|
40
|
+
silence_warnings do
|
41
|
+
SafeYAML::YAML_ENGINE = REAL_YAML_ENGINE
|
42
|
+
SafeYAML::LIBYAML_VERSION = REAL_LIBYAML_VERSION
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_check_libyaml_version(warning_expected, yaml_engine, libyaml_version=nil)
|
47
|
+
silence_warnings do
|
48
|
+
SafeYAML.const_set("YAML_ENGINE", yaml_engine)
|
49
|
+
SafeYAML.const_set("LIBYAML_VERSION", libyaml_version)
|
50
|
+
Kernel.send(warning_expected ? :should_receive : :should_not_receive, :warn)
|
51
|
+
SafeYAML.check_libyaml_version
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "issues no warnings when 'Syck' is the YAML engine" do
|
56
|
+
test_check_libyaml_version(false, "syck")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "issues a warning if Psych::LIBYAML_VERSION is not defined" do
|
60
|
+
test_check_libyaml_version(true, "psych")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "issues a warning if Psych::LIBYAML_VERSION is < 0.1.6" do
|
64
|
+
test_check_libyaml_version(true, "psych", "0.1.5")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "issues no warning if Psych::LIBYAML_VERSION is == 0.1.6" do
|
68
|
+
test_check_libyaml_version(false, "psych", "0.1.6")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "issues no warning if Psych::LIBYAML_VERSION is > 0.1.6" do
|
72
|
+
test_check_libyaml_version(false, "psych", "1.0.0")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
35
76
|
describe "unsafe_load" do
|
36
77
|
if SafeYAML::YAML_ENGINE == "psych" && RUBY_VERSION >= "1.9.3"
|
37
78
|
it "allows exploits through objects defined in YAML w/ !ruby/hash via custom :[]= methods" do
|
data/spec/spec_helper.rb
CHANGED
@@ -7,12 +7,19 @@ $LOAD_PATH << File.join(HERE, "support")
|
|
7
7
|
require "yaml"
|
8
8
|
if ENV["YAMLER"] && defined?(YAML::ENGINE)
|
9
9
|
YAML::ENGINE.yamler = ENV["YAMLER"]
|
10
|
-
puts "Running specs in Ruby #{RUBY_VERSION} with '#{YAML::ENGINE.yamler}' YAML engine."
|
11
10
|
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
ruby_version = defined?(JRUBY_VERSION) ? "JRuby #{JRUBY_VERSION} in #{RUBY_VERSION} mode" : "Ruby #{RUBY_VERSION}"
|
13
|
+
yaml_engine = defined?(YAML::ENGINE) ? YAML::ENGINE.yamler : "syck"
|
14
|
+
libyaml_version = yaml_engine == "psych" && Psych.const_defined?("LIBYAML_VERSION", false) ? Psych::LIBYAML_VERSION : "N/A"
|
15
|
+
|
16
|
+
puts <<-EOM
|
17
|
+
|
18
|
+
Running #{ruby_version} with '#{yaml_engine}' YAML engine.
|
19
|
+
YAML engine version: #{YAML::VERSION}
|
20
|
+
libyaml version: #{libyaml_version}
|
21
|
+
|
22
|
+
EOM
|
16
23
|
|
17
24
|
# Caching references to these methods before loading safe_yaml in order to test
|
18
25
|
# that they aren't touched unless you actually require safe_yaml (see yaml_spec.rb).
|
data/spec/syck_resolver_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe SafeYAML::Transform::ToDate do
|
4
4
|
it "returns true when the value matches a valid Date" do
|
@@ -36,7 +36,7 @@ describe SafeYAML::Transform::ToDate do
|
|
36
36
|
success, result = subject.transform?("2012-12-01 10:33:45 +11:00")
|
37
37
|
success.should be_true
|
38
38
|
result.should == Time.utc(2012, 11, 30, 23, 33, 45)
|
39
|
-
result.gmt_offset.should == Time.
|
39
|
+
result.gmt_offset.should == Time.local(2012, 11, 30).gmt_offset
|
40
40
|
end
|
41
41
|
|
42
42
|
it "returns strings for invalid dates" do
|
data/spec/yaml_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safe_yaml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Tao
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Parse YAML safely
|
14
14
|
email: daniel.tao@gmail.com
|
@@ -16,8 +16,8 @@ executables: []
|
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
-
- .gitignore
|
20
|
-
- .travis.yml
|
19
|
+
- ".gitignore"
|
20
|
+
- ".travis.yml"
|
21
21
|
- CHANGES.md
|
22
22
|
- Gemfile
|
23
23
|
- LICENSE.txt
|
@@ -74,12 +74,12 @@ require_paths:
|
|
74
74
|
- lib
|
75
75
|
required_ruby_version: !ruby/object:Gem::Requirement
|
76
76
|
requirements:
|
77
|
-
- -
|
77
|
+
- - ">="
|
78
78
|
- !ruby/object:Gem::Version
|
79
79
|
version: 1.8.7
|
80
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
|
-
- -
|
82
|
+
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
84
|
version: '0'
|
85
85
|
requirements: []
|