Goal
Same pattern as #34-37 for the remaining ecosystems. Each language runtime has its own loader-injection env var (Python's PYTHONPATH, Ruby's RUBYOPT, JVM's JAVA_TOOL_OPTIONS, .NET's DOTNET_STARTUP_HOOKS).
Per-language env strip
Python (pytest/mypy/ruff/pip in src/cmds/python/):
PYTHONPATH, PYTHONSTARTUP, PYTHONHOME, PYTHONUSERBASE
- All
PIP_* (PIP_INDEX_URL/_EXTRA_INDEX_URL = dependency confusion → setup.py RCE)
PIP_CONFIG_FILE, PIP_TARGET, PIP_PREFIX
Ruby (rake/rspec/rubocop in src/cmds/ruby/):
RUBYOPT (-rsomemod, Ruby's NODE_OPTIONS equivalent)
RUBYLIB (PYTHONPATH equivalent)
BUNDLE_GEMFILE (alternate Gemfile that runs in eval)
BUNDLE_PATH, GEM_HOME, GEM_PATH
JVM (gradlew in src/cmds/jvm/):
JAVA_OPTS, JAVA_TOOL_OPTIONS, JDK_JAVA_OPTIONS (javaagent injection, JVM-wide)
GRADLE_OPTS, GRADLE_USER_HOME
.NET (src/cmds/dotnet/):
DOTNET_STARTUP_HOOKS (LD_PRELOAD equivalent — loads assemblies into every dotnet process)
DOTNET_ADDITIONAL_DEPS, DOTNET_SHARED_STORE, DOTNET_CLI_HOME
NUGET_PACKAGES
Args to reject
pytest -p <module>, pytest --rootdir <outside-cwd>
mypy --config-file <env-derived>
rspec --require <module>, rubocop --require <module> (Kernel.require of arbitrary path)
gradle --init-script <file>, -I <file>
pip install --index-url <attacker>, --extra-index-url <attacker>
Accepted surface (documented, not blocked)
These execute code by design — block would break the tool:
docs/security/accepted-surface.md should enumerate these as "trusted-CWD assumption" so operators know.
Goal
Same pattern as #34-37 for the remaining ecosystems. Each language runtime has its own loader-injection env var (Python's PYTHONPATH, Ruby's RUBYOPT, JVM's JAVA_TOOL_OPTIONS, .NET's DOTNET_STARTUP_HOOKS).
Per-language env strip
Python (pytest/mypy/ruff/pip in
src/cmds/python/):PYTHONPATH,PYTHONSTARTUP,PYTHONHOME,PYTHONUSERBASEPIP_*(PIP_INDEX_URL/_EXTRA_INDEX_URL= dependency confusion →setup.pyRCE)PIP_CONFIG_FILE,PIP_TARGET,PIP_PREFIXRuby (rake/rspec/rubocop in
src/cmds/ruby/):RUBYOPT(-rsomemod, Ruby's NODE_OPTIONS equivalent)RUBYLIB(PYTHONPATH equivalent)BUNDLE_GEMFILE(alternate Gemfile that runs in eval)BUNDLE_PATH,GEM_HOME,GEM_PATHJVM (gradlew in
src/cmds/jvm/):JAVA_OPTS,JAVA_TOOL_OPTIONS,JDK_JAVA_OPTIONS(javaagent injection, JVM-wide)GRADLE_OPTS,GRADLE_USER_HOME.NET (
src/cmds/dotnet/):DOTNET_STARTUP_HOOKS(LD_PRELOAD equivalent — loads assemblies into every dotnet process)DOTNET_ADDITIONAL_DEPS,DOTNET_SHARED_STORE,DOTNET_CLI_HOMENUGET_PACKAGESArgs to reject
pytest -p <module>,pytest --rootdir <outside-cwd>mypy --config-file <env-derived>rspec --require <module>,rubocop --require <module>(Kernel.requireof arbitrary path)gradle --init-script <file>,-I <file>pip install --index-url <attacker>,--extra-index-url <attacker>Accepted surface (documented, not blocked)
These execute code by design — block would break the tool:
./conftest.pyauto-import (pytest)./Rakefile(rake)./Gemfile(bundler)build.gradle{.kts}(gradle).csprojMSBuild tasks (dotnet)build.rs/ proc-macros (covered in harden(git): strip env-driven config-injection vectors + reject -c <override> in git wrapper #35)docs/security/accepted-surface.mdshould enumerate these as "trusted-CWD assumption" so operators know.