GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Fix env-var "a" collision in R front-end shell wrapper by avoiding -e in kernel launch by ajalon1 · Pull Request #756 · IRkernel/IRkernel

Conversation

@ajalon1

@ajalon1 ajalon1 commented Aug 11, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Fixes #755.

Problem

On Unix-likes, R's own front-end ($(R RHOME)/bin/R) is a POSIX shell script. Its -e/-f/--file= argument handling reuses a plain, unexported local shell variable literally named a to hold the encoded expression text before it execs into the real R binary:

-e)
  a=`(echo "${2}" && echo) | sed -e 's/ /~+~/g' | ...`
  args="${args} -e $a"
  ;;
...
exec "${R_binary}" ${args} "${@}"

Because POSIX shells retain a variable's exported attribute once it's inherited from the environment, if the shell was launched with an env var already named a (e.g. a user-set container/notebook env var), this plain reassignment silently overwrites it with the encoded -e text — and the clobbered value is inherited by the real R process via the trailing exec, for the entire lifetime of that R session.

IRkernel's generated kernelspec launches R via ["R", "--slave", "-e", "IRkernel::main()", "--args", "{connection_file}"] — exactly this vulnerable code path. So any Jupyter user with an environment variable literally named a gets it permanently corrupted the moment their kernel starts: Sys.getenv("a") returns "IRkernel::main()" instead of the real value. Renaming to A, b, etc. is unaffected. See #755 for the full root-cause writeup and repro.

Fix

On Unix-likes, installspec() now generates a kernelspec that launches via a small sh -c wrapper piping IRkernel::main() into R's stdin, instead of passing it via -e:

echo 'IRkernel::main()' | exec /path/to/R --slave --args "$0"

This sidesteps the -e/-f/--file= code path in R's front-end entirely, so the a-variable collision never happens. Windows is untouched — R's front-end there is a compiled executable rather than a shell script, so it isn't subject to this bug, and there's no sh on a plain Windows R install to run the wrapper anyway.

Testing

Verified locally against a real R install (Alpine R=4.6.0-r0, though the front-end script logic is version/platform-independent for Unix-likes):

$ docker run --rm -e a=a -e A=A -e b=b r-base:latest \
    R --slave -e 'print(Sys.getenv("a")); print(Sys.getenv("A")); print(Sys.getenv("b"))' --args /dev/null
[1] "print(Sys.getenv(\"a\"));~+~print(Sys.getenv(\"A\"));~+~print(Sys.getenv(\"b\"))"   # <- bug
[1] "A"
[1] "b"

$ docker run --rm -e a=a -e A=A -e b=b r-base:latest sh -c \
    'echo "cat(Sys.getenv(\"a\"),Sys.getenv(\"A\"),Sys.getenv(\"b\"))" | exec R --slave --args /dev/null'
a A b   # <- fixed

Also confirmed the exact sh -c string this patch's sprintf()/shQuote() call generates for a real installspec() call, and ran it end-to-end with the same env vars set, with the same passing result.

I'm aware this project's had a quiet stretch, looks like three years or so. I'm happy to adjust the approach if maintainers have a preferred direction, or if there's a reason this hasn't been a priority -- already have a workaround in our own platform. But, I wanted to file this as a self-contained, backward-compatible fix in case it's useful.

🤖 PR description generated with Claude Code

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
ajalon1 and others added 4 commits August 11, 2026 09:45
@ajalon1 @claude
fix: avoid R front-end shell wrapper's env-var-a collision in kernel …
981783c
…launch

On Unix-likes, R's own front-end (`$(R RHOME)/bin/R`) is a POSIX shell
script whose `-e`/`-f`/`--file=` argument handling reuses a plain,
unexported local shell variable literally named `a` to hold the encoded
expression text before it execs into the real R binary. Since POSIX
shells retain a variable's exported attribute once inherited from the
environment, this silently clobbers a pre-existing exported environment
variable named `a` for the entire lifetime of the R process.

IRkernel's generated kernelspec launches R via `-e "IRkernel::main()"`,
so any Jupyter user with an environment variable literally named `a`
had it permanently corrupted at kernel startup (e.g. Sys.getenv("a")
would return "IRkernel::main()" instead of the real value).

Fix: on Unix-likes, installspec() now generates a kernelspec that
launches via a small `sh -c` wrapper piping the startup expression into
R's stdin, instead of passing it via `-e`, which sidesteps the
vulnerable code path entirely. Windows is unaffected (R's front-end
there is a compiled executable, not a shell script) and keeps its
original launch mechanism.

Fixes IRkernel#755

Co-Authored-By: Claude Sonnet 5 <[email protected]>
@ajalon1
chore: cleanup docstring, lint
1c476dd
@ajalon1
chore: cleanup docstring
b01937c
@ajalon1
chore: shorten inline comment
24ff54a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Sys.getenv("a") returns the kernel's own -e argument text instead of the env var's value (R front-end wrapper "a" variable collision)

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@ajalon1
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.