safe_yaml 1.0.1 → 1.0.2
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.
- 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: []
|