Skip to content

Commit 622eecc

Browse files
justin808claude
andcommitted
SECURITY: Fix command injection vulnerabilities in generators
Replace unsafe string interpolation with array-based system calls to prevent command injection attacks in npm/yarn/pnpm/bun commands. Security fixes: - install_generator.rb: Fix TypeScript package installation - base_generator.rb: Fix all package manager install commands - react_with_redux_generator.rb: Refactor to use safe array-based calls Risk: HIGH - Command injection could allow arbitrary code execution on developer machines during generator usage. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b037c6a commit 622eecc

File tree

3 files changed

+27
-19
lines changed

3 files changed

+27
-19
lines changed

lib/generators/react_on_rails/base_generator.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,13 @@ def add_js_dependencies
105105
def install_js_dependencies
106106
# Detect which package manager to use
107107
success = if File.exist?(File.join(destination_root, "yarn.lock"))
108-
run "yarn install"
108+
system("yarn", "install")
109109
elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
110-
run "pnpm install"
110+
system("pnpm", "install")
111111
elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
112112
File.exist?(File.join(destination_root, "package.json"))
113113
# Use npm for package-lock.json or as default fallback
114-
run "npm install"
114+
system("npm", "install")
115115
else
116116
true # No package manager detected, skip
117117
end
@@ -173,7 +173,7 @@ def add_react_on_rails_package
173173
return if add_npm_dependencies(react_on_rails_pkg)
174174

175175
puts "Using direct npm commands as fallback"
176-
success = run "npm install #{react_on_rails_pkg.join(' ')}"
176+
success = system("npm", "install", *react_on_rails_pkg)
177177
handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
178178
end
179179

@@ -189,7 +189,7 @@ def add_react_dependencies
189189
]
190190
return if add_npm_dependencies(react_deps)
191191

192-
success = run "npm install #{react_deps.join(' ')}"
192+
success = system("npm", "install", *react_deps)
193193
handle_npm_failure("React dependencies", react_deps) unless success
194194
end
195195

@@ -203,7 +203,7 @@ def add_css_dependencies
203203
]
204204
return if add_npm_dependencies(css_deps)
205205

206-
success = run "npm install #{css_deps.join(' ')}"
206+
success = system("npm", "install", *css_deps)
207207
handle_npm_failure("CSS dependencies", css_deps) unless success
208208
end
209209

@@ -215,7 +215,7 @@ def add_dev_dependencies
215215
]
216216
return if add_npm_dependencies(dev_deps, dev: true)
217217

218-
success = run "npm install --save-dev #{dev_deps.join(' ')}"
218+
success = system("npm", "install", "--save-dev", *dev_deps)
219219
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
220220
end
221221

lib/generators/react_on_rails/install_generator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def install_typescript_dependencies
339339
return if add_npm_dependencies(typescript_packages, dev: true)
340340

341341
# Fallback to npm if GeneratorHelper fails
342-
success = run "npm install --save-dev #{typescript_packages.join(' ')}"
342+
success = system("npm", "install", "--save-dev", *typescript_packages)
343343
return if success
344344

345345
warning = <<~MSG.strip

lib/generators/react_on_rails/react_with_redux_generator.rb

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,12 @@ def add_redux_npm_dependencies
9292
private
9393

9494
def install_packages_with_fallback(packages, dev:, package_manager:)
95-
packages_str = packages.join(" ")
96-
install_command = build_install_command(package_manager, dev, packages_str)
95+
install_args = build_install_args(package_manager, dev, packages)
9796

98-
success = system(install_command)
97+
success = system(*install_args)
9998
return if success
10099

100+
install_command = install_args.join(" ")
101101
warning = <<~MSG.strip
102102
⚠️ Failed to install Redux dependencies automatically.
103103
@@ -107,22 +107,30 @@ def install_packages_with_fallback(packages, dev:, package_manager:)
107107
GeneratorMessages.add_warning(warning)
108108
end
109109

110-
def build_install_command(package_manager, dev, packages_str)
110+
def build_install_args(package_manager, dev, packages)
111111
# Security: Validate package manager to prevent command injection
112112
allowed_package_managers = %w[npm yarn pnpm bun].freeze
113113
unless allowed_package_managers.include?(package_manager)
114114
raise ArgumentError, "Invalid package manager: #{package_manager}"
115115
end
116116

117-
commands = {
118-
"npm" => { dev: "npm install --save-dev", prod: "npm install" },
119-
"yarn" => { dev: "yarn add --dev", prod: "yarn add" },
120-
"pnpm" => { dev: "pnpm add --save-dev", prod: "pnpm add" },
121-
"bun" => { dev: "bun add --dev", prod: "bun add" }
117+
base_commands = {
118+
"npm" => %w[npm install],
119+
"yarn" => %w[yarn add],
120+
"pnpm" => %w[pnpm add],
121+
"bun" => %w[bun add]
122122
}
123123

124-
command_type = dev ? :dev : :prod
125-
"#{commands[package_manager][command_type]} #{packages_str}"
124+
base_args = base_commands[package_manager].dup
125+
base_args << dev_flag_for(package_manager) if dev
126+
base_args + packages
127+
end
128+
129+
def dev_flag_for(package_manager)
130+
case package_manager
131+
when "npm", "pnpm" then "--save-dev"
132+
when "yarn", "bun" then "--dev"
133+
end
126134
end
127135

128136
def add_redux_specific_messages

0 commit comments

Comments
 (0)