security(PER-8550): drop unused @amplitude production dependencies - #1357
Draft
pranavz28 wants to merge 1 commit into
Draft
security(PER-8550): drop unused @amplitude production dependencies#1357pranavz28 wants to merge 1 commit into
pranavz28 wants to merge 1 commit into
Conversation
Move @amplitude/analytics-browser and @amplitude/plugin-session-replay-browser from dependencies to devDependencies. They are build-time-only peer dependencies of @browserstack/utils (itself a devDependency, bundled into dist/ by vite), so they were never needed at consumer install time. Consumers of @percy/storybook no longer install 22 @amplitude/* packages (~48M) into node_modules. The emitted dist/ bundle is byte-for-byte identical before and after. Co-Authored-By: Claude Fable 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.
What
Moves the two Amplitude packages out of production
dependencies:"dependencies": { - "@amplitude/analytics-browser": "2.35.4", - "@amplitude/plugin-session-replay-browser": "1.25.16", "@percy/cli-command": "^1.31.10", ... "devDependencies": { + "@amplitude/analytics-browser": "2.35.4", + "@amplitude/plugin-session-replay-browser": "1.25.16", "@babel/cli": "^7.23.0",package.jsonis the only file changed.yarn.lockis untouched — a yarn v1 lockfile does not record the dev/prod distinction, and the version specifiers are unchanged, soyarn install --frozen-lockfilestill validates against the existing lockfile.Effect: consumers installing
@percy/storybookno longer pull 22@amplitude/*packages (~48 MB) intonode_modules.Correcting the ticket's threat model
PER-8635 describes a "credential exfiltration chain (Combined CVSS 8.4)" in which Amplitude session replay captures the BrowserStack access key from the connect form. That chain does not exist in the shipped artifact, but the reasoning needs correcting in both directions — the ticket overstates the risk, and the obvious "these are unused, just delete them" reading is also wrong.
The packages are not unreferenced
git grep -i amplitudeacrosssrc/returns zero hits — this repo's own code never imports, initializes, or configures Amplitude. But they are not stray, either.@browserstack/utils@5.10.0declares both aspeerDependencies, and@browserstack/utilsis pulled in transitively by@browserstack/design-stackand@browserstack/review-viewer. Its barrel entry point contains real side-effect imports:dist/amplitude.jsthere does contain genuineinit/sessionReplayPlugin/setUserIdcode. So the two entries inpackage.jsonwere satisfying a peer dependency, not sitting unused.Deleting them outright is therefore not viable — it breaks the build:
Hence the move to
devDependenciesrather than a deletion: the specifier must resolve at bundle time, but nothing needs it at consumer install time.Why no Amplitude code reaches the browser
@browserstack/utilssets"sideEffects": false, so Rollup tree-shakes those side-effect-only imports away — nothing in this addon references any Amplitude export. Rollup must still resolve the specifier before it can shake it, which is exactly why the build fails when the package is absent but the output stays clean when it is present.Verified empirically —
grep -ri amplitude dist/returns zero hits across all 56 emitted files, both before and after this change. The bundle is also byte-for-byte identical before and after (sha256 over all ofdist/), confirming the change is a pure packaging move with no runtime effect.So there is no Amplitude initialization, no session replay recorder, and no analytics network path in the distributed
dist/manager.js. The ticket's claim that the packages "ride along in the bundle and can be activated in a consumer's browser context" is not supported.Does moving to
devDependenciesbreak consumers? No — verified end-to-endReasonable reviewer concern:
@browserstack/utilsdeclares the two Amplitude packages as non-optionalpeerDependencies, so if a consumer received@browserstack/utilsbut not Amplitude, resolution could fail. Checked all three links in that chain.1. Are the peers declared optional? No.
@browserstack/utils@5.10.0has nopeerDependenciesMetablock at all, so none of its peers are optional:2. Does a consumer ever receive
@browserstack/utils? No — and this is what makes the peer question moot.@browserstack/utilsis adevDependencyof@percy/storybook, as are the@browserstack/design-stackand@browserstack/review-viewerpackages that pull it in. The publisheddependenciesare only:No
@browserstack/*package is a production dependency, so no consumer install ever creates a peer relationship for Amplitude to satisfy.3. Is it bundled or resolved at runtime? Bundled. Vite inlines
@browserstack/utils(and design-stack / review-viewer) into the emitted chunks. Grepping the packed tarball, zero@browserstackspecifiers survive in any published code file — the only matches anywhere are thedevDependenciesentries inpackage.json, which npm ignores for consumers. The complete set of bare (non-relative) imports in the shipped browser chunks isrequire("util")(a Node builtin), plus the entry point:Note also that
package.jsonfilesexcludesdist/componentsanddist/hooks— the Babel output that does carry bare@browserstack/design-stackimports is never published. Only the self-contained Vite chunks and the server-side files ship.Clean-room consumer install. Packed the built package with
npm packand installed the tarball into an empty throwaway project:npm install <tarball>npm ls @percy/storybookUNMET PEER DEPENDENCYmarkers@amplitude/*in consumer tree@browserstack/*in consumer tree@browserstackrefs in installed@percy/storybookcodeSo the peer requirement binds only at build time in this repo, where Amplitude is still installed as a
devDependency— andyarn buildpasses with no peer warnings.Pre-existing peer-version mismatch (unchanged by this PR, but relevant here)
@browserstack/utilspeer-wants exact@amplitude/analytics-browser@2.11.7and@amplitude/plugin-session-replay-browser@1.12.1, while this repo pins2.35.4and1.25.16. That mismatch predates this PR — the versions are carried over untouched. Yarn v1 does not enforce peer ranges (and emits no warning here), and since the Amplitude code is tree-shaken out entirely, the divergence has no effect on the output. Flagging it for whoever evaluates the peer question, since it means the declared peer contract was already not being honoured.Recommended severity change
node_modules, implying telemetry that does not exist), not an active exfiltration path.masteratc0b6dd4(PR security: keep BrowserStack creds server-side + validate/gate privileged server channels (PER-8544, PER-8545) #1330):src/server/projectConfig.cjsno longer returns credentials to the browser, and carries the comment "Do NOT send the BrowserStack username/access key back to the browser." ThePROJECT_CONFIG_LOADEDpayload now emits onlycredentialsValid,project,projectDetails,hasValidToken, andlastBuild. No change was made to that file here.Deliberately not changed
src/components/BrowserStackConnect.jsx(type={showAccessKey ? 'text' : 'password'}) is left as-is. The ticket flags it as an exposure vector only because it assumed a session replay recorder was capturing the DOM. With no recorder running, it is a conventional UX affordance that every major product ships, and removing it would be a usability regression bought with no security gain.maskSelector/privacySelectorconfiguration was added — there is no Amplitude initialization in this codebase to configure.src/server/projectConfig.cjsis untouched (already fixed by security: keep BrowserStack creds server-side + validate/gate privileged server channels (PER-8544, PER-8545) #1330, see above).Validation
@amplitudeinpackage.jsondependenciesyarn install --frozen-lockfileyarn.lockyarn list --productionamplitude packagesyarn buildassert-prod-bundleguarddist/bundle hashes vs. pre-changegrep -ri amplitude dist/yarn lintgit diffscopepackage.jsononlyTests:
yarn testruns 405 specs with 42 failures — but these are pre-existing and environmental, not caused by this change. Every failure traces to a Chromium download 404 on this Apple Silicon machine (storage.googleapis.com/chromium-browser-snapshots/Mac_Arm/1300314/chrome-mac.zip). Running the identical suite against unmodifiedmasterproduces exactly the same result (405 specs, 42 failed, same 102 Chromium-404 log lines), so the suite is unaffected. CI should be treated as the authority here.🤖 Generated with Claude Code