From cf90fbfed2b1d345404459b489a9df2115437d58 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 4 Jun 2026 18:45:18 +0900 Subject: [PATCH] [ruby/rubygems] Reject non-String executables and bindir with a clear error A non-String executable name or bindir previously raised TypeError from File.basename or File.join. Guard the type so verify_spec raises Gem::InstallError instead of aborting with an unexpected exception. https://github.com/ruby/rubygems/commit/89bf13a11b Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/rubygems/installer.rb | 4 +++- test/rubygems/test_gem_installer.rb | 32 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 7163e356ea..a6e1dc4730 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -713,10 +713,12 @@ class Gem::Installer raise Gem::InstallError, "#{spec} has an invalid dependencies" end - if spec.executables.any? {|name| name != File.basename(name) || /\A\.\.?\z|\R/.match?(name) } + if spec.executables.any? {|name| !name.is_a?(String) || name != File.basename(name) || /\A\.\.?\z|\R/.match?(name) } raise Gem::InstallError, "#{spec} has an invalid executable" end + raise Gem::InstallError, "#{spec} has an invalid bindir" unless spec.bindir.is_a?(String) + expanded_gem_dir = File.expand_path(gem_dir) expanded_bindir = File.expand_path(File.join(gem_dir, spec.bindir)) unless expanded_bindir == expanded_gem_dir || expanded_bindir.start_with?("#{expanded_gem_dir}/") diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index decd6def17..8947694f53 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -2013,6 +2013,38 @@ class TestGemInstaller < Gem::InstallerTestCase end end + def test_pre_install_checks_non_string_executable + spec = util_spec "malicious", "1" + def spec.validate(*args); end + spec.executables = [nil] + + installer = Gem::Installer.for_spec spec + installer.gem_home = @gemhome + + use_ui @ui do + e = assert_raise Gem::InstallError do + installer.pre_install_checks + end + assert_equal "# has an invalid executable", e.message + end + end + + def test_pre_install_checks_non_string_bindir + spec = util_spec "malicious", "1" + def spec.validate(*args); end + spec.bindir = true + + installer = Gem::Installer.for_spec spec + installer.gem_home = @gemhome + + use_ui @ui do + e = assert_raise Gem::InstallError do + installer.pre_install_checks + end + assert_equal "# has an invalid bindir", e.message + end + end + def test_pre_install_checks_malicious_platform_before_eval gem_with_ill_formatted_platform = File.expand_path("packages/ill-formatted-platform-1.0.0.10.gem", __dir__)