Repository navigation
fix(security): fail-closed CLI signature verification + https/browserstack.com redirect allowlist [DEVA11Y-473] - #46
Merged
Conversation
…VA11Y-473] followRedirects()/followWithGet() returned any Location target, and URLSession.shared auto-followed every hop, so an https -> http (or off-domain) redirect would fetch the CLI archive in cleartext or from an arbitrary host before our code saw the URL. Route the HEAD/GET resolution and the archive download through a session whose delegate vetoes any hop that is not https on browserstack.com or a subdomain, and re-check the vetoed Location / final response URL after each request as a backstop. The initial URL is still governed by parseOverride(), so an HTTPS override to a mirror keeps working as long as it does not redirect off-domain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…[DEVA11Y-473] verifyArchiveChecksum aborted only on a digest mismatch. A sidecar that could not be derived, returned non-2xx, failed to fetch, or was not a 64-char hex digest let the archive be extracted and executed unverified, so blocking or corrupting the .sha256 bypassed the check entirely (Security retest of DEVA11Y-473 @806f98cb). Every one of those paths now throws before extraction. The sidecar fetch also goes through the redirect-guarded session. README updated to describe the plugin's fail-closed behaviour. MERGE GATE: sdk-assets.browserstack.com does not publish <asset>.sha256 yet (403 for all six platform binaries as of 2026-10-16), so this commit makes every plugin run fail until SDK assets ships the sidecars. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
…sum [DEVA11Y-473] The CDN does not and will not publish <asset>.sha256 sidecars, so the checksum path could never pass and every run failed. Security accepted the Linux residual risk on DEVA11Y-473 on condition the checksum path is removed entirely and the binary's own signature is verified, failing closed: - macOS: codesign --verify --strict against a Developer ID requirement pinned to BrowserStack's Team ID YQ5FZQ855D. - Windows: Authenticode status must be Valid with an O=BrowserStack, Inc. signer. - Linux: the build is unsigned; logs the accepted risk and proceeds. The check runs on the staged binary before chmod/publish, on cache hits (a cached binary that fails is discarded and re-downloaded, covering caches filled by older unverified plugin versions), and on the final published binary, since publish can keep a concurrent build's copy. verifyArchiveChecksum, sha256Hex and the sidecar fetch are removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Crash0v3rrid3
marked this pull request as ready for review
October 21, 2026 10:20
Collaborator
Author
|
@rahul-bs @gobind-singh Ready for Security review. This is the rework you asked for on DEVA11Y-473 (comment 2471198):
The launcher scripts are handled separately under DEVA11Y-474. The Windows path is not exercised in CI (there is no Windows runner); details are in the description. |
…checksum CI jobs [DEVA11Y-474] The bash/zsh/fish launchers verified the CLI against a <asset>.sha256 sidecar that the CDN never publishes, and proceeded unverified when it was missing or malformed: the same bypass Security reopened DEVA11Y-473 over. Replace verify_binary_integrity with verify_binary_signature, mirroring the SwiftPM plugin (#46): on macOS, `codesign --verify --strict` against a Developer ID requirement pinned to Team YQ5FZQ855D, run on the extracted binary before chmod/publish. Failure refuses to run and drops the cached zip so the next run re-downloads instead of re-extracting the same payload after a 304. Linux is unsigned and passes through (accepted risk, DEVA11Y-473); any other OS is refused. CI: replace the two checksum jobs, which asserted the fail-open behaviour and waited on sidecars that will never ship, with tests/launcher-signature/run_tests.sh: - matrix: each launcher's function accepts the real CLI and refuses flipped-byte, ad-hoc-signed, unsigned and missing binaries; - published: the latest macOS arm64/x64 releases satisfy the Team-pinned requirement, so a re-signed release turns CI red first. Self-update .sha256 files regenerated for the edited launchers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ate case [DEVA11Y-474] The suite lifted verify_binary_integrity by name, which no longer exists, and drove download_binary with OS=macos and unsigned fixtures that the new signature check refuses before the guard's outcome is observable. Run the guard cases with OS=linux, where the real verify_binary_signature passes through by design, so they still execute only real code. Add case 9 (macOS): the real codesign check must refuse an unsigned payload with exit 2, remove the staged binary and the zip, and leave an existing cached binary intact. 75/75 locally. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nature-verification fix(security): fail-closed signature check in the launchers; replace checksum CI jobs [DEVA11Y-474]
nmnishant-browserstack
approved these changes
Oct 22, 2026
Crash0v3rrid3
pushed a commit
that referenced
this pull request
Oct 23, 2026
…erride [DEVA11Y-479][DEVA11Y-488] (#50) * fix(security): allowlist browserstack.com for the download URL override [DEVA11Y-479][DEVA11Y-488] parseOverride() now rejects any --download-url / BROWSERSTACK_A11Y_CLI_DOWNLOAD_URL whose host is not browserstack.com or a subdomain, using the same policy PR #46 applies to redirect hops. The file:// branches in resolveOverrideArtifact() and download() are removed, and download() refuses any URL outside the policy. Adds tests/download-url-policy, which lifts parseOverride verbatim and checks off-domain, userinfo, look-alike, IP, non-https, file:// and bare-path inputs. Wired into spm-smoke-test.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(security): reject '.' as a CLI cache version [DEVA11Y-479] extractVersion() accepted a redirect filename ending in '-..zip' as version '.', which resolves to the cache root itself. Reject it, and cover the version parser in tests/download-url-policy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: drop the download-url-policy job from spm-smoke-test.yml [DEVA11Y-479] Keeps the PR to the scope of the Security retest. The suite stays in tests/download-url-policy and runs locally. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run tests/download-url-policy in spm-smoke-test.yml [DEVA11Y-479] Restores the download-url-policy job so the override allowlist is checked on every PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(security): exercise RedirectPolicyDelegate's redirect callback offline [DEVA11Y-479][DEVA11Y-488] The suite checked isAllowedRedirectTarget directly but never the delegate that applies it to every redirect hop, so bypassing the delegate kept every case green. Lift RedirectPolicyDelegate from the plugin and drive its willPerformHTTPRedirection callback with an unstarted task: follow allowed https targets, veto http, off-domain, look-alike and file hops. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Nishant Maurya <nmnishant@outlook.in> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Why
The Security retest of DEVA11Y-473 at
806f98cbfound two gaps:.sha256file was missing, unreachable or malformed.followRedirects()/download()accepted any redirect target, so anhttp://or off-domain hop would be followed.URLSession.sharedalso auto-follows redirects.The CDN (
sdk-assets.browserstack.com) does not and will not publish checksums, so a checksum could never be verified. Security agreed to verify the binary's own code signature instead, and accepted the Linux residual risk with conditions (comment 2471198).What
f882c50– redirect allowlisthttpsonbrowserstack.com/*.browserstack.com.Locationand the finalresponse.urlare re-checked as a backstop.parseOverride()(HTTPS only).b8046c3– signature verification, failing closed (replaces the checksum approach in2e23e29)/usr/bin/codesign --verify --strictwith a Developer ID requirement pinned to TeamYQ5FZQ855D.Get-AuthenticodeSignaturemust beValid, with anO=BrowserStack, Inc.signer.verifyArchiveChecksum,sha256Hexand the sidecar fetch are removed entirely. README updated.Testing
Requirement check, run against the real 1.62.1 macOS binary:
End-to-end via
swift package … scan(macOS arm64, real network):YQ5FZQ855D) restored, run succeedscode object is not signed at all, rejected before chmod/publish; good cache untouched, no staging leftovershttp://sdk-assets.browserstack.com/…CI: all checks green, including
a11y-scan end-to-end (SwiftPM).Not tested: the Windows Authenticode path. I had no Windows host and CI has no Windows job. The signer (
BrowserStack, Inc., Sectigo Public Code Signing CA R36) was confirmed from the realbinary-win-x64.execertificate table.Out of scope
scripts/*/cli.sh): they don't yet verify the binary's signature. Tracked in DEVA11Y-474, per Security's condition 3.🤖 Generated with Claude Code