Skip to content

fix(wallets): remove browser environment check from createServerSigner#1900

Open
guilleasz-crossmint wants to merge 1 commit into
mainfrom
devin/1780588919-remove-server-signer-window-check
Open

fix(wallets): remove browser environment check from createServerSigner#1900
guilleasz-crossmint wants to merge 1 commit into
mainfrom
devin/1780588919-remove-server-signer-window-check

Conversation

@guilleasz-crossmint
Copy link
Copy Markdown
Contributor

@guilleasz-crossmint guilleasz-crossmint commented Jun 4, 2026

Description

Removes the typeof window !== "undefined" guard from createServerSigner. The check prevented calling the function from browser context, but the console app needs to derive server signer addresses client-side (e.g. in the create wallet modal). The "server" in "server signer" refers to where the keys are stored, not where the derivation runs.

Test plan

  • Existing unit tests continue to pass — no behavioral change other than removing the runtime guard
  • Verified ESM/CJS builds succeed without the window check

Package updates

  • @crossmint/wallets-sdk: patch (changeset added)

Link to Devin session: https://crossmint.devinenterprise.com/sessions/ad482efc604a499cbc47a8690419621c
Requested by: @guilleasz-crossmint


Open in Devin Review

@devin-ai-integration
Copy link
Copy Markdown
Contributor

Original prompt from Guille

SYSTEM:
=== BEGIN THREAD HISTORY ===
Guillermo Aszyn (U06MHK4CG0Y): @Devin créate a new branch for merging wallets-v1 and main together in Crossmint-sdk, solve the merge conflicts, if doubts ask me

Devin (U084HH3JUG2): Devin is running, you can send messages in this thread!

Talk to Devin in this thread

💡 Tip: Type mute to stop Devin from reading your messages

Devin (U084HH3JUG2): On it! I'll create a branch to merge wallets-v1 and main together in crossmint-sdk and resolve any conflicts.

Devin (U084HH3JUG2): PR title suggestion: wallets: merge wallets-v1 branch into main
Should I use this, or would you prefer a different title?

Guillermo Aszyn (U06MHK4CG0Y): The branch should merge main into wallets-v1 and should base wallets-v1 title format is fine i was asking doubts regarding when is not clear how to solve merge conflicts not trivial stuff

Devin (U084HH3JUG2): Woke up.

Devin (U084HH3JUG2): Understood - PR will target wallets-v1 branch. I'll only ask when merge conflict resolution is genuinely ambiguous. Creating the PR now.

Devin (U084HH3JUG2):

Closed PR #1659 - wallets: merge main into wallets-v1
Repo: crossmint-sdk

Devin (U084HH3JUG2): Devin is awaiting instructions

Devin is awaiting instructions

Devin (U084HH3JUG2): PR is ready with all CI checks passing (lint, build &amp; test, smoke tests): <https://github.com/Crossmint/crossmint-sdk/pull/1659|crossmint-sdk`#`1659> (<https://crossmint.devinenterprise.com/review/Crossmint/crossmint-sdk/pull/1659|Devin Review>)
Key conflict resolutions:
• Integrated main's server signer support into wallets-v1's refactored API (recovery/signers naming)
• Added server signer handling to validateSigners() and registerSigners() with deriveServerSignerDetails
• Fixed activity.tsx demo app to use .events instead of .data (matching the actual WalletsActivityResponseUnstableDto type)
• Added resolveSigner() helper in Wallet class for unified device/server signer resol... (1657 chars truncated...)

@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jun 4, 2026

🦋 Changeset detected

Latest commit: 704841f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@crossmint/wallets-sdk Patch
@crossmint/wallets-quickstart-devkit Patch
@crossmint/wallets-playground-react Patch
@crossmint/client-sdk-react-base Patch
@crossmint/client-sdk-react-native-ui Patch
@crossmint/client-sdk-react-ui Patch
@crossmint/wallets-playground-expo Patch
@crossmint/auth-ssr-nextjs-demo Patch
@crossmint/client-sdk-nextjs-starter Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 4, 2026

Security Review

  • Private key exposure in browser context (packages/wallets/src/utils/server-signers/createServerSigner.ts): Removing the typeof window !== "undefined" guard now allows createServerSigner to run in a browser. The function returns a ServerSigner object that includes keyBytes — the raw 32-byte HKDF-derived private key — alongside the address. Browser callers that only need the address still receive and hold the private key in memory, where it is accessible via DevTools, error-reporting serializers, and React/Redux state inspection.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
packages/wallets/src/utils/server-signers/createServerSigner.ts:41-48
**Private key material returned in browser context**

`createServerSigner` now runs in browsers, but its return type still includes `keyBytes` — the raw 32-byte derived private key. If a caller in the browser console app invokes this function only to obtain the `address` for display, the raw private key is still materialized in JS memory and sits in the returned object. It can easily leak through `console.log(signer)`, spreading into React/Redux DevTools state, or error-reporting serialization.

If the motivating use-case is purely address derivation (display in the wallet-creation modal), consider extracting an address-only helper — e.g., `deriveServerSignerAddress` is already importable directly — so that `keyBytes` is never created in the browser. Alternatively, the `ServerSigner` return type could split into separate browser-safe and server-only shapes, with `keyBytes` only present on the server variant.

Reviews (1): Last reviewed commit: "fix(wallets): remove browser environment..." | Re-trigger Greptile

@devin-ai-integration
Copy link
Copy Markdown
Contributor

Appreciate the cold-blooded vigilance 🦎, but this concern doesn't hold up on closer inspection.

The keyBytes are derived from a secret that the caller already possesses and passes in — if the secret is in browser memory (e.g. the user typed it into a form), then the derived key material is no more sensitive than what's already there. The secret is the private key material; keyBytes is just a deterministic derivation of it.

Splitting into an address-only helper would mean re-exporting the low-level deriveServerSignerAddress — exactly what we were asked NOT to do in PR #1887. The whole point of createServerSigner is to be the single public API surface for this functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant