Skip to content

Commit 334bff6

Browse files
committed
Patch YAML to allow only some Gem classes to be unmarshalled
1 parent c69bd75 commit 334bff6

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

config/initializers/forbidden_yaml.rb

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# XXX: This is purely a monkey patch to close the exploit vector for now, a more
2+
# permanent solution should be pushed upstream into rubygems.
3+
4+
require "rubygems"
5+
6+
# Assert we're using Psych
7+
abort "Use Psych for YAML, install libyaml and reinstall ruby" unless YAML == Psych
8+
9+
module Psych
10+
class ForbiddenClassException < Exception
11+
end
12+
13+
module Visitors
14+
class WhitelistedToRuby < ToRuby
15+
WHITELIST = %w(
16+
Gem::Dependency
17+
Gem::Platform
18+
Gem::Requirement
19+
Gem::Specification
20+
Gem::Version
21+
Gem::Version::Requirement
22+
)
23+
24+
private
25+
26+
def resolve_class klassname
27+
raise ForbiddenClassException, "Forbidden class in YAML: #{klassname}" unless WHITELIST.include? klassname
28+
super klassname
29+
end
30+
end
31+
end
32+
end
33+
34+
module Gem
35+
class Specification
36+
def self.from_yaml input
37+
input = normalize_yaml_input input
38+
nodes = Psych.parse input
39+
spec = Psych::Visitors::WhitelistedToRuby.new.accept nodes
40+
41+
if spec && spec.class == FalseClass then
42+
raise Gem::EndOfYAMLException
43+
end
44+
45+
unless Gem::Specification === spec then
46+
raise Gem::Exception, "YAML data doesn't evaluate to gem specification"
47+
end
48+
49+
unless (spec.instance_variables.include? '@specification_version' or
50+
spec.instance_variables.include? :@specification_version) and
51+
spec.instance_variable_get :@specification_version
52+
spec.instance_variable_set :@specification_version,
53+
NONEXISTENT_SPECIFICATION_VERSION
54+
end
55+
56+
spec
57+
end
58+
end
59+
end

0 commit comments

Comments
 (0)