Repository navigation
Comparing changes
Open a pull request
base repository: browserstack/browserstack-local-ruby
base: locsec/WI-72531096
head repository: browserstack/browserstack-local-ruby
compare: master
- 16 commits
- 9 files changed
- 4 contributors
Commits on Aug 7, 2026
-
test: fix pre-existing unit-test failures (green the suite)
The unit suite could not be installed or run on any modern Ruby, and 3 integration tests errored in credential-less environments. This greens the baseline without weakening any test. Dependency/harness rot: - Gemfile/Gemfile.lock used an insecure `http://rubygems.org` source, which no longer serves the spec index -> `bundle install` failed. Switched to `https://`. - The lockfile pinned json 1.8.3 / minitest 5.8.4 / rake 12.3.3 with `BUNDLED WITH 1.11.2`. json 1.8.3 cannot build its native extension on Ruby 3.x, and the pinned Bundler was force-installed. Regenerated the lockfile with current, buildable versions and added the common Linux platforms for CI portability. Integration tests: - test_check_pid, test_is_running and test_multiple_binary start the real BrowserStackLocal binary and open a tunnel, so they require a valid BROWSERSTACK_ACCESS_KEY and network access. They now skip (rather than error) when no access key is present, so the suite stays green in bare environments. When a key is set they run in full, unchanged. Run the suite: bundle install bundle exec rake test Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for ee74327 - Browse repository at this point
Copy the full SHA ee74327View commit details
Commits on Aug 12, 2026
-
build: verify gem integrity at install time (CVE-2020-8130 hardening)
The Gemfile/Gemfile.lock fetched gems over plain http://rubygems.org with BUNDLED WITH 1.11.2 and no CHECKSUMS block, so nothing verified the content of a downloaded gem. rake executes arbitrary code from the Rakefile at test time, so a substituted tarball would run as the developer. Context: CVE-2020-8130 / GHSA-jppv-gw3r-w3q8 is an OS command injection in Rake::FileList, patched in rake 12.3.3. The old lockfile already pinned 12.3.3 so it was not itself vulnerable; the gap was that the *delivery* of that gem was unverifiable. This moves to rake 13.4.2 and makes delivery verifiable. - Gemfile.lock: regenerated with Bundler 2.7.1, adding a CHECKSUMS block with per-gem SHA-256 digests that Bundler verifies on every bundle install. - Gemfile: drop `gem "json"`. lib/ only uses JSON.parse/JSON.dump from the json default gem that ships with Ruby, and the gemspec declares no dependency on it, so a third-party json was a redundant build-time component -- and a native extension that fails to compile against Homebrew ruby@3.2 headers. - .gitignore: ignore .bundle/ and vendor/bundle/. .bundle/config can carry disable_checksum_validation, which would silently switch the new verification off, so it must never be committed. Verified: every digest matches the SHA-256 rubygems.org publishes for that version. Flipping one digest makes bundle install abort with "Bundler found mismatched checksums" (exit 37, nothing installed); with the CHECKSUMS block removed the same install exits 0 and performs no verification at all. Suite: 23 runs, 40 assertions, 0 failures, 0 errors, 3 skips. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 524db87 - Browse repository at this point
Copy the full SHA 524db87View commit details -
fix: run the binary directly in verify_binary instead of through a sh…
…ell (CWE-78) verify_binary built its command by string concatenation: IO.popen(bin_path + " --version") The single-string form of IO.popen hands the whole thing to /bin/sh, so any shell metacharacter in the binary path is interpreted rather than treated as part of a filename. bin_path is assembled from @ordered_paths — the expanded home directory, Dir.pwd and Dir.tmpdir — none of which are sanitised, so a directory name containing ";" or "$()" turns a routine version check into arbitrary command execution. Reproduced end to end through the public LocalBinary#binary_path entry point. The array form execs the binary directly and never involves a shell, which also fixes a long-standing benign failure: a path containing a space (common on macOS and Windows) used to be split by the shell, so verification of a perfectly good cached binary failed and the binary was deleted and re-downloaded on every run. Deliberately not changed here, each tracked separately: the fail-open rescue in this same method, the TOCTOU window between verification and execution, and the other shell-string call sites in local.rb. A character allowlist on the path was considered and rejected — with no shell involved it adds nothing, and it would reject the legitimate space-containing paths this change fixes. Adds two regression tests, both verified to fail before this change.Configuration menu - View commit details
-
Copy full SHA for db623c3 - Browse repository at this point
Copy the full SHA db623c3View commit details -
chore: scope-limited scanner suppression on the fixed verify_binary line
The dangerous-exec rule fires on any non-static first argument to IO.popen and does not model the array form, so it reports the fixed line as well as the vulnerable one it replaced -- the same rule is already open against master on the pre-fix line. Comment-only; no behaviour change. Suppression is scoped to this one rule on this one line, with the reason stated inline, so every other IO.popen/exec finding in this file still reports.
Configuration menu - View commit details
-
Copy full SHA for ab48704 - Browse repository at this point
Copy the full SHA ab48704View commit details -
test: pin the array-form behaviour with a real binary at a hostile path
The existing injection test returns false post-fix via Errno::ENOENT rather than by demonstrating that the named file is executed verbatim, so it would also pass under a character-allowlist remediation instead of the array form. Putting the metacharacters in the directory name of a real, executable script asserts both halves at once: the injected command never runs, and the legitimate binary at that hostile-looking path still verifies. This is the same shape as the reproduction that exercises the vulnerability through $HOME. Verified to fail before the fix on the injection assertion.
Configuration menu - View commit details
-
Copy full SHA for e766c21 - Browse repository at this point
Copy the full SHA e766c21View commit details
Commits on Sep 21, 2026
-
fix: create the logfile without a shell (CWE-78 command injection)
Local#start created the logfile with system("echo > #{@logfile}") # Windows system("echo '' > '#{@logfile}'") # Unix Both pass the caller-supplied logfile path through /bin/sh (or cmd.exe), so shell metacharacters in the path are interpreted as commands. A logfile value like "log' ; touch /tmp/pwned ; echo 'x" (Unix) or "NUL & calc.exe" (Windows) runs arbitrary OS commands as the user running the gem (CWE-78). Replace the block with a shell-free create/truncate: mkdir_p the parent dir, then File.write(@logfile, ""), raising LocalException if the path is unwritable. File.write treats the path purely as a filename, so no shell is involved. This also fixes logfile paths containing spaces or a missing subdirectory, which the old shell form silently failed on. Mirrors the fix already shipped in the python binding. Adds BrowserStackLocalLogfileTest with two regression tests (no creds/network): a metacharacter payload no longer executes, and a space/missing-dir path is created literally. Both fail on the pre-fix code.Configuration menu - View commit details
-
Copy full SHA for b7b0d1a - Browse repository at this point
Copy the full SHA b7b0d1aView commit details -
fix: redact access key in public command accessor and inspect (CWE-312)
The public `command` method returned the start command string with the BrowserStack access key interpolated verbatim, so any caller that logged it (CI output, test runner logs, APM/error trackers) leaked the credential to a wider audience than the key itself. Ruby's default #inspect had the same problem, dumping @key when a Local instance was logged or raised. - command now returns the command with the key masked as [REDACTED] - start_command takes an optional redact flag; the execution path (start_command_args array, and the string form on legacy Ruby) keeps the real key, so the tunnel is unaffected - add a redacting #inspect so the key is never dumped by object inspection Proxy password is intentionally left visible (existing behaviour/tests). Adds regression tests that fail on the pre-fix code. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 9529fed - Browse repository at this point
Copy the full SHA 9529fedView commit details
Commits on Sep 24, 2026
-
Merge pull request #42 from browserstack/chore/green-unit-tests
build: verify gem integrity at install time + green the unit-test baseline
Configuration menu - View commit details
-
Copy full SHA for f12fa92 - Browse repository at this point
Copy the full SHA f12fa92View commit details -
Merge pull request #43 from browserstack/locsec/WI-cf38e835
fix: run the binary directly in verify_binary instead of through a shell (CWE-78)
Configuration menu - View commit details
-
Copy full SHA for 861f33a - Browse repository at this point
Copy the full SHA 861f33aView commit details -
Merge pull request #45 from browserstack/locsec/WI-09e205d7
fix: create the logfile without a shell (CWE-78 command injection)
Configuration menu - View commit details
-
Copy full SHA for 614d949 - Browse repository at this point
Copy the full SHA 614d949View commit details -
Merge pull request #46 from browserstack/locsec/WI-72531096
ci: pin gem-push workflow actions to immutable commit SHAs
Configuration menu - View commit details
-
Copy full SHA for a506d5a - Browse repository at this point
Copy the full SHA a506d5aView commit details -
Merge pull request #47 from browserstack/locsec/WI-a20414f5
fix: redact access key in public command accessor and inspect (CWE-312)
Configuration menu - View commit details
-
Copy full SHA for 32f5f4f - Browse repository at this point
Copy the full SHA 32f5f4fView commit details
Commits on Sep 25, 2026
-
Configuration menu - View commit details
-
Copy full SHA for 123c882 - Browse repository at this point
Copy the full SHA 123c882View commit details -
Merge pull request #48 from browserstack/release_1.5.1
Release 1.5.1
Configuration menu - View commit details
-
Copy full SHA for 5341a73 - Browse repository at this point
Copy the full SHA 5341a73View commit details -
ci: skip Bundler install in gem-push workflow
The Build + Publish run failed at ruby/setup-ruby (https://github.com/browserstack/browserstack-local-ruby/actions/runs/36133351430). Gemfile.lock now says BUNDLED WITH 2.7.1 (regenerated in ee74327), so by default setup-ruby runs `gem install bundler -v 2.7.1`. Bundler 2.7 needs Ruby >= 3.2, so the install fails on the job's Ruby 2.6.10: There are no versions of bundler (= 2.7.1) compatible with your Ruby & RubyGems bundler requires Ruby version >= 3.2.0. This job only runs `gem build` and `gem push`, and neither uses Bundler. Set `bundler: none` so setup-ruby skips the install. The publish Ruby stays at 2.6.10. The lockfile keeps Bundler 2.7.1 and its CHECKSUMS block, because downgrading to Bundler 2.4.x (the last line that supports Ruby 2.6) would drop the 524db87 integrity hardening. Verified: the workflow YAML parses; the pinned setup-ruby SHA (v1.324.0) documents 'none' as "nothing is done"; `gem build *.gemspec` succeeds without Bundler. The workflow itself was not run, since it publishes to RubyGems. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for fccdb05 - Browse repository at this point
Copy the full SHA fccdb05View commit details -
Merge pull request #49 from browserstack/fix/gem-push-skip-bundler
ci: skip Bundler install in gem-push workflow
Configuration menu - View commit details
-
Copy full SHA for 60a2b46 - Browse repository at this point
Copy the full SHA 60a2b46View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff locsec/WI-72531096...master