Skip to content

Commit 9c92ad5

Browse files
committed
Security: randomize path of git wrapper script
Before, the `:git_wrapper_path` was a somewhat predictable value and located in `/tmp` by default, which is world-writable. That meant that there was a chance (albeit very small) that another process could guess the path and overwrite it with something malicious. Fix by randomly generating a path name so that the git wrapper script location cannot be predicted. This change should be transparent to capistrano users since the `:git_wrapper_path` is only intended to be used internally. If you need a predictable value for this path, set a custom value for `:git_wrapper_path` in your `deploy.rb` file.
1 parent c676e64 commit 9c92ad5

4 files changed

Lines changed: 9 additions & 12 deletions

File tree

features/step_definitions/assertions.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
end
66

77
Then(/^git wrapper permissions are 0700$/) do
8-
permissions_test = %Q([ $(stat -c "%a" #{TestApp.git_wrapper_path.shellescape}) == "700" ])
8+
permissions_test = %Q([ $(stat -c "%a" #{TestApp.git_wrapper_path_glob}) == "700" ])
99
_stdout, _stderr, status = vagrant_cli_command("ssh -c #{permissions_test.shellescape}")
1010

1111
expect(status).to be_success

lib/capistrano/scm/git.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
require "capistrano/scm/plugin"
22
require "cgi"
3+
require "securerandom"
34
require "shellwords"
45
require "uri"
56

67
class Capistrano::SCM::Git < Capistrano::SCM::Plugin
78
def set_defaults
89
set_if_empty :git_shallow_clone, false
910
set_if_empty :git_wrapper_path, lambda {
10-
# Try to avoid permissions issues when multiple users deploy the same app
11-
# by using different file names in the same dir for each deployer and stage.
12-
suffix = %i(application stage local_user).map { |key| fetch(key).to_s }.join("-")
13-
"#{fetch(:tmp_dir)}/git-ssh-#{suffix}.sh"
11+
# Use a unique name that won't collide with other deployments, and
12+
# that cannot be guessed by other processes that have access to /tmp.
13+
"#{fetch(:tmp_dir)}/git-ssh-#{SecureRandom.hex(10)}.sh"
1414
}
1515
set_if_empty :git_environmental_variables, lambda {
1616
{

spec/lib/capistrano/scm/git_spec.rb

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,10 @@ module Capistrano
2828
end
2929

3030
describe "#set_defaults" do
31-
it "makes git_wrapper_path using application, stage, and local_user" do
31+
it "makes git_wrapper_path using a random hex value" do
3232
env.set(:tmp_dir, "/tmp")
33-
env.set(:application, "my_app")
34-
env.set(:stage, "staging")
35-
env.set(:local_user, "(Git Web User) via ShipIt")
3633
subject.set_defaults
37-
expect(env.fetch(:git_wrapper_path)).to eq("/tmp/git-ssh-my_app-staging-(Git Web User) via ShipIt.sh")
34+
expect(env.fetch(:git_wrapper_path)).to match(%r{/tmp/git-ssh-\h{20}\.sh})
3835
end
3936

4037
it "makes git_max_concurrent_connections" do

spec/support/test_app.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ def move_configuration_to_custom_location(location)
185185
FileUtils.mv(config_path, location)
186186
end
187187

188-
def git_wrapper_path
189-
"/tmp/git-ssh-my_app_name-#{stage}-#{current_user}.sh"
188+
def git_wrapper_path_glob
189+
"/tmp/git-ssh-*.sh"
190190
end
191191

192192
def with_clean_bundler_env(&block)

0 commit comments

Comments
 (0)