Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: browserstack/browserstack-local-ruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: locsec/WI-72531096
Choose a base ref
...
head repository: browserstack/browserstack-local-ruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 16 commits
  • 9 files changed
  • 4 contributors

Commits on Aug 7, 2026

  1. 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>
    07souravkunda and claude committed Aug 7, 2026
    Configuration menu
    Copy the full SHA
    ee74327 View commit details
    Browse the repository at this point in the history

Commits on Aug 12, 2026

  1. 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>
    07souravkunda and claude committed Aug 12, 2026
    Configuration menu
    Copy the full SHA
    524db87 View commit details
    Browse the repository at this point in the history
  2. 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.
    07souravkunda committed Aug 12, 2026
    Configuration menu
    Copy the full SHA
    db623c3 View commit details
    Browse the repository at this point in the history
  3. 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.
    07souravkunda committed Aug 12, 2026
    Configuration menu
    Copy the full SHA
    ab48704 View commit details
    Browse the repository at this point in the history
  4. 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.
    07souravkunda committed Aug 12, 2026
    Configuration menu
    Copy the full SHA
    e766c21 View commit details
    Browse the repository at this point in the history

Commits on Sep 21, 2026

  1. 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.
    07souravkunda committed Sep 21, 2026
    Configuration menu
    Copy the full SHA
    b7b0d1a View commit details
    Browse the repository at this point in the history
  2. 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>
    07souravkunda and claude committed Sep 21, 2026
    Configuration menu
    Copy the full SHA
    9529fed View commit details
    Browse the repository at this point in the history

Commits on Sep 24, 2026

  1. Merge pull request #42 from browserstack/chore/green-unit-tests

    build: verify gem integrity at install time + green the unit-test baseline
    07souravkunda authored Sep 24, 2026
    Configuration menu
    Copy the full SHA
    f12fa92 View commit details
    Browse the repository at this point in the history
  2. Merge pull request #43 from browserstack/locsec/WI-cf38e835

    fix: run the binary directly in verify_binary instead of through a shell (CWE-78)
    07souravkunda authored Sep 24, 2026
    Configuration menu
    Copy the full SHA
    861f33a View commit details
    Browse the repository at this point in the history
  3. Merge pull request #45 from browserstack/locsec/WI-09e205d7

    fix: create the logfile without a shell (CWE-78 command injection)
    07souravkunda authored Sep 24, 2026
    Configuration menu
    Copy the full SHA
    614d949 View commit details
    Browse the repository at this point in the history
  4. Merge pull request #46 from browserstack/locsec/WI-72531096

    ci: pin gem-push workflow actions to immutable commit SHAs
    07souravkunda authored Sep 24, 2026
    Configuration menu
    Copy the full SHA
    a506d5a View commit details
    Browse the repository at this point in the history
  5. Merge pull request #47 from browserstack/locsec/WI-a20414f5

    fix: redact access key in public command accessor and inspect (CWE-312)
    07souravkunda authored Sep 24, 2026
    Configuration menu
    Copy the full SHA
    32f5f4f View commit details
    Browse the repository at this point in the history

Commits on Sep 25, 2026

  1. bump: version

    07souravkunda committed Sep 25, 2026
    Configuration menu
    Copy the full SHA
    123c882 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    5341a73 View commit details
    Browse the repository at this point in the history
  3. 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>
    07souravkunda and claude committed Sep 25, 2026
    Configuration menu
    Copy the full SHA
    fccdb05 View commit details
    Browse the repository at this point in the history
  4. Merge pull request #49 from browserstack/fix/gem-push-skip-bundler

    ci: skip Bundler install in gem-push workflow
    AdityaHirapara authored Sep 25, 2026
    Configuration menu
    Copy the full SHA
    60a2b46 View commit details
    Browse the repository at this point in the history
Loading