bundler-audit 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.travis.yml +5 -2
- data/ChangeLog.md +25 -0
- data/Gemfile +2 -1
- data/README.md +12 -1
- data/Rakefile +11 -13
- data/data/ruby-advisory-db/CONTRIBUTORS.md +9 -0
- data/data/ruby-advisory-db/gems/actionpack/OSVDB-100524.yml +20 -0
- data/data/ruby-advisory-db/gems/actionpack/OSVDB-100525.yml +21 -0
- data/data/ruby-advisory-db/gems/actionpack/OSVDB-100526.yml +27 -0
- data/data/ruby-advisory-db/gems/actionpack/OSVDB-100527.yml +24 -0
- data/data/ruby-advisory-db/gems/actionpack/OSVDB-100528.yml +22 -0
- data/data/ruby-advisory-db/gems/actionpack/OSVDB-103439.yml +24 -0
- data/data/ruby-advisory-db/gems/actionpack/OSVDB-103440.yml +22 -0
- data/data/ruby-advisory-db/gems/activerecord/OSVDB-103438.yml +23 -0
- data/data/ruby-advisory-db/gems/arabic-prawn/OSVDB-104365.yml +15 -0
- data/data/ruby-advisory-db/gems/cocaine/OSVDB-98835.yml +2 -2
- data/data/ruby-advisory-db/gems/crack/OSVDB-90742.yml +1 -1
- data/data/ruby-advisory-db/gems/curl/OSVDB-91230.yml +1 -1
- data/data/ruby-advisory-db/gems/echor/OSVDB-102129.yml +11 -0
- data/data/ruby-advisory-db/gems/echor/OSVDB-102130.yml +10 -0
- data/data/ruby-advisory-db/gems/gitlab-grit/OSVDB-99370.yml +14 -0
- data/data/ruby-advisory-db/gems/httparty/OSVDB-90741.yml +3 -8
- data/data/ruby-advisory-db/gems/i18n/OSVDB-100528.yml +17 -0
- data/data/ruby-advisory-db/gems/nokogiri/OSVDB-101179.yml +12 -0
- data/data/ruby-advisory-db/gems/nokogiri/OSVDB-101458.yml +15 -0
- data/data/ruby-advisory-db/gems/nori/OSVDB-90196.yml +1 -1
- data/data/ruby-advisory-db/gems/omniauth-facebook/OSVDB-99693.yml +22 -0
- data/data/ruby-advisory-db/gems/omniauth-facebook/OSVDB-99888.yml +17 -0
- data/data/ruby-advisory-db/gems/paperclip/OSVDB-103151.yml +13 -0
- data/data/ruby-advisory-db/gems/paratrooper-newrelic/OSVDB-101839.yml +12 -0
- data/data/ruby-advisory-db/gems/paratrooper-pingdom/OSVDB-101847.yml +13 -0
- data/data/ruby-advisory-db/gems/rack/OSVDB-89939.yml +1 -1
- data/data/ruby-advisory-db/gems/rbovirt/OSVDB-104080.yml +20 -0
- data/data/ruby-advisory-db/gems/rgpg/OSVDB-95948.yml +2 -1
- data/data/ruby-advisory-db/gems/sfpagent/OSVDB-105971.yml +13 -0
- data/data/ruby-advisory-db/gems/spree/OSVDB-91216.yml +3 -2
- data/data/ruby-advisory-db/gems/spree/OSVDB-91217.yml +3 -2
- data/data/ruby-advisory-db/gems/spree/OSVDB-91218.yml +3 -2
- data/data/ruby-advisory-db/gems/spree/OSVDB-91219.yml +3 -2
- data/data/ruby-advisory-db/gems/sprout/OSVDB-100598.yml +14 -0
- data/data/ruby-advisory-db/gems/webbynode/OSVDB-100920.yml +11 -0
- data/data/ruby-advisory-db/gems/will_paginate/OSVDB-101138.yml +15 -0
- data/data/ruby-advisory-db/spec/advisory_example.rb +3 -3
- data/data/ruby-advisory-db/spec/gems_spec.rb +3 -4
- data/data/ruby-advisory-db.ts +1 -0
- data/gemspec.yml +2 -0
- data/lib/bundler/audit/advisory.rb +5 -1
- data/lib/bundler/audit/cli.rb +13 -7
- data/lib/bundler/audit/database.rb +7 -4
- data/lib/bundler/audit/scanner.rb +101 -3
- data/lib/bundler/audit/version.rb +2 -2
- data/lib/bundler/audit.rb +1 -1
- data/spec/advisory_spec.rb +78 -27
- data/spec/audit_spec.rb +1 -1
- data/spec/bundle/insecure_sources/Gemfile +1 -1
- data/spec/bundle/secure/Gemfile +2 -2
- data/spec/bundle/unpatched_gems/Gemfile +1 -1
- data/spec/database_spec.rb +68 -11
- data/spec/fixtures/not_a_hash.yml +2 -0
- data/spec/integration_spec.rb +14 -73
- data/spec/scanner_spec.rb +8 -8
- data/spec/spec_helper.rb +43 -0
- metadata +71 -30
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
gem: rgpg
|
|
3
3
|
osvdb: 95948
|
|
4
|
+
cve: 2013-4203
|
|
4
5
|
url: http://www.osvdb.org/show/osvdb/95948
|
|
5
6
|
title: Ruby rgpg Gem Shell Command Injection Vulnerabilities
|
|
6
7
|
date: 2013-08-02
|
|
@@ -8,6 +9,6 @@ description: |
|
|
|
8
9
|
rgpg Gem for Ruby contains a flaw in the GpgHelper module (lib/rgpg/gpg_helper.rb).
|
|
9
10
|
The issue is due to the program failing to properly sanitize user-supplied input before being used in the system() function for execution.
|
|
10
11
|
This may allow a remote attacker to execute arbitrary commands.
|
|
11
|
-
cvss_v2:
|
|
12
|
+
cvss_v2: 7.5
|
|
12
13
|
patched_versions:
|
|
13
14
|
- ">= 0.2.3"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
gem: sfpagent
|
|
3
|
+
cve:
|
|
4
|
+
osvdb: 105971
|
|
5
|
+
url: http://www.osvdb.org/show/osvdb/105971
|
|
6
|
+
title: sfpagent Gem for Ruby Remote Command Injection
|
|
7
|
+
date: 2014-04-16
|
|
8
|
+
description: sfpagent Gem for Ruby contains a flaw that is triggered as JSON[body]
|
|
9
|
+
input is not properly sanitized when handling module names with shell metacharacters.
|
|
10
|
+
This may allow a context-dependent attacker to execute arbitrary commands.
|
|
11
|
+
cvss_v2:
|
|
12
|
+
patched_versions:
|
|
13
|
+
- ">= 0.4.15"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
---
|
|
1
|
+
---
|
|
2
2
|
gem: spree
|
|
3
3
|
cve: 2013-1656
|
|
4
4
|
osvdb: 91216
|
|
@@ -7,4 +7,5 @@ title: Spree promotion_actions_controller.rb promotion_action Parameter Arbitrar
|
|
|
7
7
|
date: 2013-02-21
|
|
8
8
|
description: Spree contains a flaw that is triggered when handling input passed via the 'promotion_action' parameter to promotion_actions_controller.rb. This may allow a remote authenticated attacker to instantiate arbitrary Ruby objects and potentially execute arbitrary commands.
|
|
9
9
|
cvss_v2: 4.3
|
|
10
|
-
patched_versions:
|
|
10
|
+
patched_versions:
|
|
11
|
+
- ">= 2.0.0"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
---
|
|
1
|
+
---
|
|
2
2
|
gem: spree
|
|
3
3
|
cve: 2013-1656
|
|
4
4
|
osvdb: 91217
|
|
@@ -7,4 +7,5 @@ title: Spree payment_methods_controller.rb payment_method Parameter Arbitrary Ru
|
|
|
7
7
|
date: 2013-02-21
|
|
8
8
|
description: Spree contains a flaw that is triggered when handling input passed via the 'payment_method' parameter to payment_methods_controller.rb. This may allow a remote authenticated attacker to instantiate arbitrary Ruby objects and potentially execute arbitrary commands.
|
|
9
9
|
cvss_v2: 4.3
|
|
10
|
-
patched_versions:
|
|
10
|
+
patched_versions:
|
|
11
|
+
- ">= 2.0.0"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
---
|
|
1
|
+
---
|
|
2
2
|
gem: spree
|
|
3
3
|
cve: 2013-1656
|
|
4
4
|
osvdb: 91218
|
|
@@ -7,4 +7,5 @@ title: Spree promotions_controller.rb calculator_type Parameter Arbitrary Ruby O
|
|
|
7
7
|
date: 2013-02-21
|
|
8
8
|
description: Spree contains a flaw that is triggered when handling input passed via the 'calculator_type' parameter to promotions_controller.rb. This may allow a remote authenticated attacker to instantiate arbitrary Ruby objects and potentially execute arbitrary commands.
|
|
9
9
|
cvss_v2: 4.3
|
|
10
|
-
patched_versions:
|
|
10
|
+
patched_versions:
|
|
11
|
+
- ">= 2.0.0"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
---
|
|
1
|
+
---
|
|
2
2
|
gem: spree
|
|
3
3
|
cve: 2013-1656
|
|
4
4
|
osvdb: 91219
|
|
@@ -7,4 +7,5 @@ title: Spree promotion_rules_controller.rb promotion_rule Parameter Arbitrary Ru
|
|
|
7
7
|
date: 2013-02-21
|
|
8
8
|
description: Spree contains a flaw that is triggered when handling input passed via the 'promotion_rule' parameter to promotion_rules_controller.rb. This may allow a remote authenticated attacker to instantiate arbitrary Ruby objects and potentially execute arbitrary commands.
|
|
9
9
|
cvss_v2: 4.3
|
|
10
|
-
patched_versions:
|
|
10
|
+
patched_versions:
|
|
11
|
+
- ">= 2.0.0"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
gem: sprout
|
|
3
|
+
cve: 2013-6421
|
|
4
|
+
osvdb: 100598
|
|
5
|
+
url: http://www.osvdb.org/show/osvdb/100598
|
|
6
|
+
title: Sprout Gem for Ruby contains a flaw
|
|
7
|
+
date: 2013-12-02
|
|
8
|
+
description: sprout Gem for Ruby contains a flaw in the unpack_zip() function in archive_unpacker.rb.
|
|
9
|
+
The issue is due to the program failing to properly sanitize input passed via the 'zip_file', 'dir',
|
|
10
|
+
'zip_name', and 'output' parameters. This may allow a context-dependent attacker to execute arbitrary code.
|
|
11
|
+
cvss_v2: 7.5
|
|
12
|
+
patched_versions:
|
|
13
|
+
unaffected_versions:
|
|
14
|
+
- '< 0.7.246'
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
gem: webbynode
|
|
3
|
+
osvdb: 100920
|
|
4
|
+
url: http://osvdb.org/show/osvdb/100920
|
|
5
|
+
title: Webbynode Gem for Ruby contains a flaw
|
|
6
|
+
date: 2013-12-12
|
|
7
|
+
description: Webbynode Gem for Ruby contains a flaw in notify.rb that is triggered
|
|
8
|
+
when handling a specially crafted growlnotify message. This may allow a
|
|
9
|
+
context-dependent attacker to execute arbitrary commands.
|
|
10
|
+
cvss_v2: 7.5
|
|
11
|
+
patched_versions:
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
gem: will_paginate
|
|
3
|
+
osvdb: 101138
|
|
4
|
+
cve: 2013-6459
|
|
5
|
+
url: http://osvdb.org/show/osvdb/101138
|
|
6
|
+
title: will_paginate Gem for Ruby Generated Pagination Link Unspecified XSS
|
|
7
|
+
date: 2013-09-19
|
|
8
|
+
description: will_paginate Gem for Ruby contains a flaw that allows a cross-site scripting (XSS) attack.
|
|
9
|
+
This flaw exists because the application does not validate certain unspecified input related to
|
|
10
|
+
generated pagination links before returning it to the user. This may allow an attacker to create
|
|
11
|
+
a specially crafted request that would execute arbitrary script code in a users browser within the
|
|
12
|
+
trust relationship between their browser and the server.
|
|
13
|
+
cvss_v2: 4.3
|
|
14
|
+
patched_versions:
|
|
15
|
+
- ">= 3.0.5"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
load File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
|
2
2
|
require 'yaml'
|
|
3
3
|
|
|
4
4
|
shared_examples_for 'Advisory' do |path|
|
|
@@ -131,7 +131,7 @@ shared_examples_for 'Advisory' do |path|
|
|
|
131
131
|
it "should contain valid RubyGem version requirements" do
|
|
132
132
|
lambda {
|
|
133
133
|
Gem::Requirement.new(*subject)
|
|
134
|
-
}.should_not raise_error
|
|
134
|
+
}.should_not raise_error
|
|
135
135
|
end
|
|
136
136
|
end
|
|
137
137
|
end
|
|
@@ -155,7 +155,7 @@ shared_examples_for 'Advisory' do |path|
|
|
|
155
155
|
it "should contain valid RubyGem version requirements" do
|
|
156
156
|
lambda {
|
|
157
157
|
Gem::Requirement.new(*subject)
|
|
158
|
-
}.should_not raise_error
|
|
158
|
+
}.should_not raise_error
|
|
159
159
|
end
|
|
160
160
|
end
|
|
161
161
|
end
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
load File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
|
2
|
+
load File.join(File.dirname(__FILE__), 'advisory_example.rb')
|
|
4
3
|
describe "gems" do
|
|
5
|
-
Dir.glob('gems/*/*.yml') do |path|
|
|
4
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../gems/*/*.yml')) do |path|
|
|
6
5
|
include_examples 'Advisory', path
|
|
7
6
|
end
|
|
8
7
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2014-02-11 00:45:58 UTC
|
data/gemspec.yml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
2
|
+
# Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
3
3
|
#
|
|
4
4
|
# bundler-audit is free software: you can redistribute it and/or modify
|
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -25,6 +25,8 @@ module Bundler
|
|
|
25
25
|
:title,
|
|
26
26
|
:description,
|
|
27
27
|
:cvss_v2,
|
|
28
|
+
:cve,
|
|
29
|
+
:osvdb,
|
|
28
30
|
:unaffected_versions,
|
|
29
31
|
:patched_versions)
|
|
30
32
|
|
|
@@ -59,6 +61,8 @@ module Bundler
|
|
|
59
61
|
data['title'],
|
|
60
62
|
data['description'],
|
|
61
63
|
data['cvss_v2'],
|
|
64
|
+
data['cve'],
|
|
65
|
+
data['osvdb'],
|
|
62
66
|
parse_versions[data['unaffected_versions']],
|
|
63
67
|
parse_versions[data['patched_versions']]
|
|
64
68
|
)
|
data/lib/bundler/audit/cli.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
2
|
+
# Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
3
3
|
#
|
|
4
4
|
# bundler-audit is free software: you can redistribute it and/or modify
|
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -18,12 +18,13 @@
|
|
|
18
18
|
require 'bundler/audit/scanner'
|
|
19
19
|
require 'bundler/audit/version'
|
|
20
20
|
|
|
21
|
+
require 'thor'
|
|
21
22
|
require 'bundler'
|
|
22
23
|
require 'bundler/vendored_thor'
|
|
23
24
|
|
|
24
25
|
module Bundler
|
|
25
26
|
module Audit
|
|
26
|
-
class CLI < Thor
|
|
27
|
+
class CLI < ::Thor
|
|
27
28
|
|
|
28
29
|
default_task :check
|
|
29
30
|
map '--version' => :version
|
|
@@ -48,10 +49,10 @@ module Bundler
|
|
|
48
49
|
end
|
|
49
50
|
|
|
50
51
|
if vulnerable
|
|
51
|
-
say "
|
|
52
|
+
say "Vulnerabilities found!", :red
|
|
52
53
|
exit 1
|
|
53
54
|
else
|
|
54
|
-
say "No
|
|
55
|
+
say "No vulnerabilities found", :green
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
|
|
@@ -72,9 +73,9 @@ module Bundler
|
|
|
72
73
|
|
|
73
74
|
protected
|
|
74
75
|
|
|
75
|
-
def say(
|
|
76
|
+
def say(message="", color=nil)
|
|
76
77
|
color = nil unless $stdout.tty?
|
|
77
|
-
super(
|
|
78
|
+
super(message.to_s, color)
|
|
78
79
|
end
|
|
79
80
|
|
|
80
81
|
def print_warning(message)
|
|
@@ -89,7 +90,12 @@ module Bundler
|
|
|
89
90
|
say gem.version
|
|
90
91
|
|
|
91
92
|
say "Advisory: ", :red
|
|
92
|
-
|
|
93
|
+
|
|
94
|
+
if advisory.cve
|
|
95
|
+
say "CVE-#{advisory.cve}"
|
|
96
|
+
elsif advisory.osvdb
|
|
97
|
+
say advisory.osvdb
|
|
98
|
+
end
|
|
93
99
|
|
|
94
100
|
say "Criticality: ", :red
|
|
95
101
|
case advisory.criticality
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
2
|
+
# Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
3
3
|
#
|
|
4
4
|
# bundler-audit is free software: you can redistribute it and/or modify
|
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -34,8 +34,11 @@ module Bundler
|
|
|
34
34
|
# Default path to the ruby-advisory-db
|
|
35
35
|
VENDORED_PATH = File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','data','ruby-advisory-db'))
|
|
36
36
|
|
|
37
|
+
# Timestamp for when the database was last updated
|
|
38
|
+
VENDORED_TIMESTAMP = Time.parse(File.read("#{VENDORED_PATH}.ts")).utc
|
|
39
|
+
|
|
37
40
|
# Path to the user's copy of the ruby-advisory-db
|
|
38
|
-
USER_PATH = File.join(
|
|
41
|
+
USER_PATH = File.expand_path(File.join(ENV['HOME'],'.local','share','ruby-advisory-db'))
|
|
39
42
|
|
|
40
43
|
# The path to the advisory database
|
|
41
44
|
attr_reader :path
|
|
@@ -65,8 +68,8 @@ module Bundler
|
|
|
65
68
|
#
|
|
66
69
|
def self.path
|
|
67
70
|
if File.directory?(USER_PATH)
|
|
68
|
-
t1 = Dir.chdir(USER_PATH) { Time.parse(`git log --pretty="%cd" -1`) }
|
|
69
|
-
t2 =
|
|
71
|
+
t1 = Dir.chdir(USER_PATH) { Time.parse(`git log --date=iso8601 --pretty="%cd" -1`) }
|
|
72
|
+
t2 = VENDORED_TIMESTAMP
|
|
70
73
|
|
|
71
74
|
if t1 >= t2 then USER_PATH
|
|
72
75
|
else VENDORED_PATH
|
|
@@ -2,7 +2,10 @@ require 'bundler'
|
|
|
2
2
|
require 'bundler/audit/database'
|
|
3
3
|
require 'bundler/lockfile_parser'
|
|
4
4
|
|
|
5
|
+
require 'ipaddr'
|
|
6
|
+
require 'resolv'
|
|
5
7
|
require 'set'
|
|
8
|
+
require 'uri'
|
|
6
9
|
|
|
7
10
|
module Bundler
|
|
8
11
|
module Audit
|
|
@@ -59,17 +62,46 @@ module Bundler
|
|
|
59
62
|
# @return [Enumerator]
|
|
60
63
|
# If no block is given, an Enumerator will be returned.
|
|
61
64
|
#
|
|
62
|
-
def scan(options={})
|
|
63
|
-
return enum_for(__method__,options) unless
|
|
65
|
+
def scan(options={},&block)
|
|
66
|
+
return enum_for(__method__,options) unless block
|
|
64
67
|
|
|
65
68
|
ignore = Set[]
|
|
66
69
|
ignore += options[:ignore] if options[:ignore]
|
|
67
70
|
|
|
71
|
+
scan_sources(options,&block)
|
|
72
|
+
scan_specs(options,&block)
|
|
73
|
+
|
|
74
|
+
return self
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#
|
|
78
|
+
# Scans the gem sources in the lockfile.
|
|
79
|
+
#
|
|
80
|
+
# @param [Hash] options
|
|
81
|
+
# Additional options.
|
|
82
|
+
#
|
|
83
|
+
# @yield [result]
|
|
84
|
+
# The given block will be passed the results of the scan.
|
|
85
|
+
#
|
|
86
|
+
# @yieldparam [InsecureSource] result
|
|
87
|
+
# A result from the scan.
|
|
88
|
+
#
|
|
89
|
+
# @return [Enumerator]
|
|
90
|
+
# If no block is given, an Enumerator will be returned.
|
|
91
|
+
#
|
|
92
|
+
# @api semipublic
|
|
93
|
+
#
|
|
94
|
+
# @since 0.4.0
|
|
95
|
+
#
|
|
96
|
+
def scan_sources(options={})
|
|
97
|
+
return enum_for(__method__,options) unless block_given?
|
|
98
|
+
|
|
68
99
|
@lockfile.sources.map do |source|
|
|
69
100
|
case source
|
|
70
101
|
when Source::Git
|
|
71
102
|
case source.uri
|
|
72
103
|
when /^git:/, /^http:/
|
|
104
|
+
next if internal_host?(source.uri)
|
|
73
105
|
yield InsecureSource.new(source.uri)
|
|
74
106
|
end
|
|
75
107
|
when Source::Rubygems
|
|
@@ -80,6 +112,35 @@ module Bundler
|
|
|
80
112
|
end
|
|
81
113
|
end
|
|
82
114
|
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# Scans the gem sources in the lockfile.
|
|
119
|
+
#
|
|
120
|
+
# @param [Hash] options
|
|
121
|
+
# Additional options.
|
|
122
|
+
#
|
|
123
|
+
# @option options [Array<String>] :ignore
|
|
124
|
+
# The advisories to ignore.
|
|
125
|
+
#
|
|
126
|
+
# @yield [result]
|
|
127
|
+
# The given block will be passed the results of the scan.
|
|
128
|
+
#
|
|
129
|
+
# @yieldparam [UnpatchedGem] result
|
|
130
|
+
# A result from the scan.
|
|
131
|
+
#
|
|
132
|
+
# @return [Enumerator]
|
|
133
|
+
# If no block is given, an Enumerator will be returned.
|
|
134
|
+
#
|
|
135
|
+
# @api semipublic
|
|
136
|
+
#
|
|
137
|
+
# @since 0.4.0
|
|
138
|
+
#
|
|
139
|
+
def scan_specs(options={})
|
|
140
|
+
return enum_for(__method__,options) unless block_given?
|
|
141
|
+
|
|
142
|
+
ignore = Set[]
|
|
143
|
+
ignore += options[:ignore] if options[:ignore]
|
|
83
144
|
|
|
84
145
|
@lockfile.specs.each do |gem|
|
|
85
146
|
@database.check_gem(gem) do |advisory|
|
|
@@ -88,10 +149,47 @@ module Bundler
|
|
|
88
149
|
end
|
|
89
150
|
end
|
|
90
151
|
end
|
|
152
|
+
end
|
|
91
153
|
|
|
92
|
-
|
|
154
|
+
private
|
|
155
|
+
|
|
156
|
+
#
|
|
157
|
+
# Determines whether a URI is internal.
|
|
158
|
+
#
|
|
159
|
+
# @param [String] uri
|
|
160
|
+
# The source URI.
|
|
161
|
+
#
|
|
162
|
+
# @return [Boolean]
|
|
163
|
+
#
|
|
164
|
+
def internal_host?(uri)
|
|
165
|
+
return unless host = URI.parse(uri).host
|
|
166
|
+
Resolv.getaddresses(host).all? { |ip| internal_ip?(ip) }
|
|
167
|
+
rescue URI::Error
|
|
168
|
+
false
|
|
93
169
|
end
|
|
94
170
|
|
|
171
|
+
# List of internal IP address ranges.
|
|
172
|
+
#
|
|
173
|
+
# @see https://tools.ietf.org/html/rfc1918#section-3
|
|
174
|
+
# @see https://tools.ietf.org/html/rfc4193#section-8
|
|
175
|
+
INTERNAL_SUBNETS = %w[
|
|
176
|
+
10.0.0.0/8
|
|
177
|
+
172.16.0.0/12
|
|
178
|
+
192.168.0.0/16
|
|
179
|
+
fc00::/7
|
|
180
|
+
].map(&IPAddr.method(:new))
|
|
181
|
+
|
|
182
|
+
#
|
|
183
|
+
# Determines whether an IP is internal.
|
|
184
|
+
#
|
|
185
|
+
# @param [String] ip
|
|
186
|
+
# The IPv4/IPv6 address.
|
|
187
|
+
#
|
|
188
|
+
# @return [Boolean]
|
|
189
|
+
#
|
|
190
|
+
def internal_ip?(ip)
|
|
191
|
+
INTERNAL_SUBNETS.any? { |subnet| subnet.include?(ip) }
|
|
192
|
+
end
|
|
95
193
|
end
|
|
96
194
|
end
|
|
97
195
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
2
|
+
# Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
3
3
|
#
|
|
4
4
|
# bundler-audit is free software: you can redistribute it and/or modify
|
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
module Bundler
|
|
19
19
|
module Audit
|
|
20
20
|
# bundler-audit version
|
|
21
|
-
VERSION = '0.
|
|
21
|
+
VERSION = '0.4.0'
|
|
22
22
|
end
|
|
23
23
|
end
|
data/lib/bundler/audit.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c) 2013 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
2
|
+
# Copyright (c) 2013-2015 Hal Brodigan (postmodern.mod3 at gmail.com)
|
|
3
3
|
#
|
|
4
4
|
# bundler-audit is free software: you can redistribute it and/or modify
|
|
5
5
|
# it under the terms of the GNU General Public License as published by
|
data/spec/advisory_spec.rb
CHANGED
|
@@ -7,50 +7,101 @@ describe Bundler::Audit::Advisory do
|
|
|
7
7
|
let(:gem) { 'actionpack' }
|
|
8
8
|
let(:id) { 'OSVDB-84243' }
|
|
9
9
|
let(:path) { File.join(root,'gems',gem,"#{id}.yml") }
|
|
10
|
+
let(:an_unaffected_version) do
|
|
11
|
+
Bundler::Audit::Advisory.load(path).unaffected_versions.map { |version_rule|
|
|
12
|
+
# For all the rules, get the individual constraints out and see if we
|
|
13
|
+
# can find a suitable one...
|
|
14
|
+
version_rule.requirements.select { |(constraint, gem_version)|
|
|
15
|
+
# We only want constraints where the version number specified is
|
|
16
|
+
# one of the unaffected version. I.E. we don't want ">", "<", or if
|
|
17
|
+
# such a thing exists, "!=" constraints.
|
|
18
|
+
['~>', '>=', '=', '<='].include?(constraint)
|
|
19
|
+
}.map { |(constraint, gem_version)|
|
|
20
|
+
# Fetch just the version component, which is a Gem::Version,
|
|
21
|
+
# and extract the string representation of the version.
|
|
22
|
+
gem_version.version
|
|
23
|
+
}
|
|
24
|
+
}.flatten.first
|
|
25
|
+
end
|
|
10
26
|
|
|
11
27
|
describe "load" do
|
|
12
28
|
let(:data) { YAML.load_file(path) }
|
|
13
29
|
|
|
14
30
|
subject { described_class.load(path) }
|
|
15
31
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
32
|
+
describe '#id' do
|
|
33
|
+
subject { super().id }
|
|
34
|
+
it { is_expected.to eq(id) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '#url' do
|
|
38
|
+
subject { super().url }
|
|
39
|
+
it { is_expected.to eq(data['url']) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#title' do
|
|
43
|
+
subject { super().title }
|
|
44
|
+
it { is_expected.to eq(data['title']) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '#cvss_v2' do
|
|
48
|
+
subject { super().cvss_v2 }
|
|
49
|
+
it { is_expected.to eq(data['cvss_v2']) }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe '#description' do
|
|
53
|
+
subject { super().description }
|
|
54
|
+
it { is_expected.to eq(data['description']) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context "YAML data not representing a hash" do
|
|
58
|
+
it "should raise an exception" do
|
|
59
|
+
path = File.expand_path('../fixtures/not_a_hash.yml', __FILE__)
|
|
60
|
+
expect {
|
|
61
|
+
Advisory.load(path)
|
|
62
|
+
}.to raise_exception("advisory data in #{path.dump} was not a Hash")
|
|
63
|
+
end
|
|
64
|
+
end
|
|
21
65
|
|
|
22
66
|
describe "#patched_versions" do
|
|
23
67
|
subject { described_class.load(path).patched_versions }
|
|
24
68
|
|
|
25
69
|
it "should all be Gem::Requirement objects" do
|
|
26
|
-
subject.all? { |version|
|
|
27
|
-
version.
|
|
28
|
-
}.
|
|
70
|
+
expect(subject.all? { |version|
|
|
71
|
+
expect(version).to be_kind_of(Gem::Requirement)
|
|
72
|
+
}).to be_truthy
|
|
29
73
|
end
|
|
30
74
|
|
|
31
75
|
it "should parse the versions" do
|
|
32
|
-
subject.map(&:to_s).
|
|
76
|
+
expect(subject.map(&:to_s)).to eq(data['patched_versions'])
|
|
33
77
|
end
|
|
34
78
|
end
|
|
35
79
|
end
|
|
36
80
|
|
|
37
81
|
describe "#criticality" do
|
|
38
82
|
context "when cvss_v2 is between 0.0 and 3.3" do
|
|
39
|
-
before {
|
|
40
|
-
|
|
41
|
-
|
|
83
|
+
before {
|
|
84
|
+
@advisory = Advisory.new
|
|
85
|
+
@advisory.cvss_v2 = 3.3
|
|
86
|
+
}
|
|
87
|
+
it { expect(@advisory.criticality).to eq(:low) }
|
|
42
88
|
end
|
|
43
89
|
|
|
44
90
|
context "when cvss_v2 is between 3.3 and 6.6" do
|
|
45
|
-
before {
|
|
91
|
+
before {
|
|
92
|
+
@advisory = Advisory.new
|
|
93
|
+
@advisory.cvss_v2 = 6.6
|
|
94
|
+
}
|
|
95
|
+
it { expect(@advisory.criticality).to eq(:medium) }
|
|
46
96
|
|
|
47
|
-
its(:criticality) { should == :medium }
|
|
48
97
|
end
|
|
49
98
|
|
|
50
99
|
context "when cvss_v2 is between 6.6 and 10.0" do
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
100
|
+
before {
|
|
101
|
+
@advisory = Advisory.new
|
|
102
|
+
@advisory.cvss_v2 = 10.0
|
|
103
|
+
}
|
|
104
|
+
it { expect(@advisory.criticality).to eq(:high) }
|
|
54
105
|
end
|
|
55
106
|
end
|
|
56
107
|
|
|
@@ -58,10 +109,10 @@ describe Bundler::Audit::Advisory do
|
|
|
58
109
|
subject { described_class.load(path) }
|
|
59
110
|
|
|
60
111
|
context "when passed a version that matches one unaffected version" do
|
|
61
|
-
let(:version) { Gem::Version.new(
|
|
112
|
+
let(:version) { Gem::Version.new(an_unaffected_version) }
|
|
62
113
|
|
|
63
114
|
it "should return true" do
|
|
64
|
-
subject.unaffected?(version).
|
|
115
|
+
expect(subject.unaffected?(version)).to be_truthy
|
|
65
116
|
end
|
|
66
117
|
end
|
|
67
118
|
|
|
@@ -69,7 +120,7 @@ describe Bundler::Audit::Advisory do
|
|
|
69
120
|
let(:version) { Gem::Version.new('3.0.9') }
|
|
70
121
|
|
|
71
122
|
it "should return false" do
|
|
72
|
-
subject.unaffected?(version).
|
|
123
|
+
expect(subject.unaffected?(version)).to be_falsey
|
|
73
124
|
end
|
|
74
125
|
end
|
|
75
126
|
end
|
|
@@ -81,7 +132,7 @@ describe Bundler::Audit::Advisory do
|
|
|
81
132
|
let(:version) { Gem::Version.new('3.1.11') }
|
|
82
133
|
|
|
83
134
|
it "should return true" do
|
|
84
|
-
subject.patched?(version).
|
|
135
|
+
expect(subject.patched?(version)).to be_truthy
|
|
85
136
|
end
|
|
86
137
|
end
|
|
87
138
|
|
|
@@ -89,7 +140,7 @@ describe Bundler::Audit::Advisory do
|
|
|
89
140
|
let(:version) { Gem::Version.new('2.9.0') }
|
|
90
141
|
|
|
91
142
|
it "should return false" do
|
|
92
|
-
subject.patched?(version).
|
|
143
|
+
expect(subject.patched?(version)).to be_falsey
|
|
93
144
|
end
|
|
94
145
|
end
|
|
95
146
|
end
|
|
@@ -101,7 +152,7 @@ describe Bundler::Audit::Advisory do
|
|
|
101
152
|
let(:version) { Gem::Version.new('3.1.11') }
|
|
102
153
|
|
|
103
154
|
it "should return false" do
|
|
104
|
-
subject.vulnerable?(version).
|
|
155
|
+
expect(subject.vulnerable?(version)).to be_falsey
|
|
105
156
|
end
|
|
106
157
|
end
|
|
107
158
|
|
|
@@ -109,17 +160,17 @@ describe Bundler::Audit::Advisory do
|
|
|
109
160
|
let(:version) { Gem::Version.new('2.9.0') }
|
|
110
161
|
|
|
111
162
|
it "should return true" do
|
|
112
|
-
subject.vulnerable?(version).
|
|
163
|
+
expect(subject.vulnerable?(version)).to be_truthy
|
|
113
164
|
end
|
|
114
165
|
|
|
115
166
|
context "when unaffected_versions is not empty" do
|
|
116
167
|
subject { described_class.load(path) }
|
|
117
168
|
|
|
118
169
|
context "when passed a version that matches one unaffected version" do
|
|
119
|
-
let(:version) { Gem::Version.new(
|
|
170
|
+
let(:version) { Gem::Version.new(an_unaffected_version) }
|
|
120
171
|
|
|
121
172
|
it "should return false" do
|
|
122
|
-
subject.vulnerable?(version).
|
|
173
|
+
expect(subject.vulnerable?(version)).to be_falsey
|
|
123
174
|
end
|
|
124
175
|
end
|
|
125
176
|
|
|
@@ -127,7 +178,7 @@ describe Bundler::Audit::Advisory do
|
|
|
127
178
|
let(:version) { Gem::Version.new('1.2.3') }
|
|
128
179
|
|
|
129
180
|
it "should return true" do
|
|
130
|
-
subject.vulnerable?(version).
|
|
181
|
+
expect(subject.vulnerable?(version)).to be_truthy
|
|
131
182
|
end
|
|
132
183
|
end
|
|
133
184
|
end
|