• Wallet secrets and merchant records are encrypted locally; StellarKey has no server-side key store or recovery operator.
  • Every signature still depends on a trustworthy device, browser, origin, build, and review by the person authorizing it.
  • Security maintenance is ongoing and the source is public, but no software (including StellarKey) can guarantee absolute security.

Security principles

  • Minimize custody: do not build an application backend that can receive keys.
  • Encrypt by default: keep sensitive local records encrypted at rest.
  • Make authority visible: show the full transaction before signing.
  • Fail closed: reject malformed storage, unsupported signing paths, unsafe callbacks, and network mismatches.
  • Keep recovery independent: a password and tested backup remain available when optional passkey unlock is used.
  • Make releases inspectable: publish source identity, checksums, dependency inventory, and disclosure instructions.

Threat model and limits

The local encryption model is designed to reduce exposure when someone reads a locked browser profile, exported encrypted backup, or encrypted merchant database without the unlock material. Transaction review, endpoint validation, and strict parsing are designed to reduce mistakes and unsafe data crossing a trust boundary. Browser security headers are designed to reduce injection, framing, and unnecessary device access.

These controls cannot protect an already-unlocked wallet on a compromised device; a malicious browser, extension, operating system, keyboard, clipboard, screen recorder, DNS response, hosting origin, dependency, or release artifact; phishing on a lookalike origin; a weak or exposed password; a compromised recovery backup; coerced device verification; or an unsafe transaction the user approves. They also cannot control Stellar consensus, Horizon or RPC operators, asset issuers, market-data services, Trezor infrastructure, or counterparties.

No design review, automated test suite, encryption algorithm, hardware wallet, passkey, or open-source process removes every vulnerability. StellarKey cannot guarantee absolute security. Use a dedicated, maintained device where practical, keep recovery material offline, verify the exact origin and release, and test new workflows with small amounts.

Vault and local data

A new wallet uses a random 256-bit master key. The browser derives a wrapping key from the wallet password using PBKDF2-HMAC-SHA-256 with a unique random salt and 600,000 iterations, then protects the master key with authenticated AES-GCM encryption. Recovery phrases, imported signing keys, contacts, and private notes are encrypted with the master key. Merchant data uses a separate random encryption key wrapped by that master key and is committed transactionally in IndexedDB.

AES-GCM detects an incorrect key or modified ciphertext; it does not make a weak password strong or protect plaintext after a successful unlock. Signing secrets are opened only for the scoped action that needs them, and in-memory byte buffers are cleared where the platform allows. JavaScript and browser memory management cannot guarantee that every temporary copy is immediately or forensically erased.

Locking removes the active vault and merchant keys from application state. It does not encrypt the account index needed to render the lock screen: each account's public key, label, and creation time remain readable to someone who can inspect the locked browser profile. A public key is enough to correlate that account's full public ledger history. Treat access to the browser profile as financially sensitive even though it does not grant signing authority.

Auto-lock reduces an unattended session window but is not a substitute for locking the device. Full backups use the encrypted version 2 envelope; legacy plaintext wallet imports are rejected. A backup is useful only if it is stored safely and has been tested.

Signing and transaction safety

StellarKey validates addresses, network identity, amounts, assets, issuers, and supported operations before constructing a transaction. The review surface shows the complete operation list, source, destination, asset identity, amount, memo, fee, and network before a software or hardware signer is invoked. Processing controls prevent accidental duplicate submission while a request is active.

After broadcast, the app exposes the transaction hash and tracks a pending transaction to a confirmed success or failure where possible. Merchant crypto charges additionally match the destination, network, asset, amount, memo, and confirmation state reported by Horizon. Temporary endpoint failure remains possible, so an interface status is not a substitute for checking the authoritative ledger before releasing high-value goods or treating a payment as final.

Passkeys and hardware wallets

Passkey unlock

On a compatible HTTPS origin, WebAuthn PRF derives an origin-bound secret after the platform authenticator requires user verification. StellarKey uses that result to unwrap the existing local vault master key. It does not receive a biometric template, export the authenticator’s private key, replace Stellar signing authority, or turn the wallet into a passkey smart account. The local passkey wrapper is not included in backups, so retain the wallet password and recovery material.

Trezor

When Trezor is selected, StellarKey sends the supported transaction description through the official Trezor Connect flow and asks the device to sign. Confirm the address and every transaction detail on the hardware display; a compromised browser can still try to present an unsafe request. StellarKey never asks for the Trezor recovery phrase. Trezor Connect and its services are an optional, separately licensed external dependency.

Release 1.0.0 uses the current stable @trezor/connect-web@9.7.3. Its optional, lazy-loaded dependency graph currently carries ten low-severity elliptic advisories through Trezor Connect's Bitcoin/UTXO support, not StellarKey's Stellar signing implementation. npm offers no fixed stable Trezor release. High and critical production advisories remain release-blocking, and this exception is re-evaluated when Trezor publishes an update.

Web and release security

Production must be served over HTTPS. The generated host policy applies a build-specific Content Security Policy, blocks framing and MIME sniffing, restricts browser permissions, separates the origin, and permits cross-origin popups needed by Trezor. The app has no dynamic API routes, server sessions, analytics script, advertising script, or cloud database. Its service worker caches only the versioned static application shell.

The CSP keeps script-src hash-bound with no unsafe-inline or unsafe-eval. Its connect-src https: and image policy are deliberately broad because user-configurable Stellar endpoints and issuer-chosen metadata or logo hosts cannot be enumerated at build time. This is an outbound-connection privacy boundary, not permission for a remote response to execute as script.

Every production build exposes the full source commit and a machine-readable release manifest. Published releases are expected to include artifact checksums and a CycloneDX software bill of materials. Compare those records with the public source. A matching identifier improves traceability but cannot alone prove that the host, build environment, or device is safe.

Ongoing security maintenance

Security is treated as an ongoing engineering process, not a one-time claim. Maintainers review security-sensitive changes and dependencies as part of release work; run type, unit, integration, browser, accessibility, static-export, dependency-audit, and bundle checks; keep unsafe or incomplete flows disabled; and investigate credible vulnerability reports. Release checks cover desktop Chromium plus iPhone and iPad WebKit profiles, while physical Trezor and installed-device behavior remain manual release checks.

The process is informed by secure-development and verification practices such as NIST’s Secure Software Development Framework and OWASP’s Application Security Verification Standard. This is a statement of direction, not a claim of NIST or OWASP certification, formal compliance, independent audit, penetration-test coverage, or freedom from defects. Public source enables independent inspection, but publication alone is not an audit.

Responsible disclosure

Report a reproducible issue privately before publishing details. Include the affected route, release or commit, browser and operating-system version, expected behavior, observed behavior, and the smallest safe reproduction. We will acknowledge and triage credible reports, but cannot promise a reward or response deadline unless a separate program says so.

Good-faith testing must use accounts and data you own or are explicitly authorized to use, avoid privacy violations and disruption, stop if sensitive data is encountered, and allow a reasonable opportunity to investigate before disclosure. This policy does not authorize testing Stellar infrastructure, hosting providers, Trezor services, asset issuers, or any other third party. The machine-readable disclosure contact is published at /.well-known/security.txt in the format defined for security.txt.

Supported release

Security fixes target the latest published build, currently StellarKey release 1.0.0, commit a52011004b480694addd7196bb038cc41ea3603f. Confirm an issue against that release when practical and name any older affected release in your report.

Older builds should be treated as unsupported unless a release notice explicitly says otherwise. A support label does not guarantee that an undiscovered vulnerability is absent or that a fix will be available on a particular schedule.

Report securely

Never include a recovery phrase, secret key, wallet password, passkey output, decrypted or encrypted wallet backup, merchant archive, customer record, or real unredacted transaction data in a report. Use a fresh testnet wallet and redact public addresses when they are not essential to the reproduction.

The button below constructs the dedicated security contact only after you activate it, which keeps the complete address out of static page markup and deters basic harvesting.

What is actually protecting you

These are not marketing numbers. Each one is read straight out of the source, and you can check them yourself in the files named beside each figure.

Vault cipherAES-256-GCM
Key derivationPBKDF2-SHA-256, 600,000 iterations
Merchant recordsXChaCha20-Poly1305, 24-byte nonce
Auto-lock15 minutes idle, adjustable
Staff PIN5 wrong tries per open app window, then 30 seconds
Hardware signingTrezor, key never enters the browser

The staff PIN throttle is client-side state in the open app window and resets after a reload or close. At roughly ten attempts per minute it is a local till deterrent, not high-security authentication. The PIN cannot sign a Stellar transaction or move money; the unlocked wallet and reviewed signing flow remain separate.

Everything that leaves this device

There is no StellarKey application server, but direct destinations vary with the network, endpoints, assets, and optional features you choose. These are the request categories and what they can reveal.

goes towhat forwhat it learns
Selected Horizon / RPC endpointBalances, history, fees, simulation, and transaction submissionYour IP, requested public accounts, and signed transactions. Never your secret key.
CoinGeckoOptional market and fiat display pricesYour IP, timing, and requested asset identifiers.
Issuer-chosen metadata / logo hostsOptional stellar.toml details and asset artworkYour IP and the asset being viewed. Loading an issuer logo can therefore disclose interest in that asset to the issuer or its image host.
FriendbotOnly when requesting testnet fundingYour IP and testnet public address.
Trezor ConnectOnly after choosing a Trezor actionConnection metadata and the supported unsigned transaction presented for device approval.
External explorerOnly after opening an explorer linkThe public account or transaction identifier you chose.

No analytics, advertising, application telemetry, or StellarKey API receives these requests. Use the browser network inspector to see the exact destinations for your configuration.

What is kept here, and how to remove it

All of it lives in this browser, on this device. Reset Wallet in Settings deletes every one of these keys, and once it is gone we cannot help you get it back, because we never had it.

Your vaultPassword-wrapped. Holds encrypted signing authority.
Merchant recordsOrders, catalogue, customers, shifts. Encrypted.
ContactsAES-GCM encrypted and available only while unlocked.
Locked account indexPublic key, label, and creation time remain readable locally.
PreferencesNetwork, currency, auto-lock, privacy mode.

How the page itself is locked down

A wallet in a browser is only as safe as the page it runs in. These headers ship with every response, and you can read them in the response yourself.

Content-Security-Policy
Application scripts require this origin and an exact build-time hash; inline evaluation is disabled. Outbound HTTPS and images remain broad for configurable endpoints and issuer metadata.
frame-ancestors: none
The app cannot be put inside someone else’s page and used to trick you.
Permissions-Policy
Camera, microphone, location and the payment API are switched off at the browser level.
Strict-Transport-Security
A year of enforced HTTPS, so the app cannot be served to you over a plain connection.
X-Content-Type-Options
The browser will not second-guess a file’s type, which closes off a whole class of trickery.
Referrer-Policy
Links out do not carry the page you came from.

What this protects you from, and what it does not

Anyone who only tells you the first half is selling something. Both halves are true and you should read the second one twice.

It protects you from

  • Somebody taking your money, because nobody but you can sign for it
  • A company freezing your account, because there is no account
  • A database of your customers leaking, because it never left your device
  • Us reading your balance, your notes or your books
  • A fee appearing later, because there is no billing relationship

It cannot protect you from

  • A stolen unlocked device, or a password written on the machine
  • Malware on the computer you are using, or a hostile browser extension
  • You approving a transaction you did not read properly
  • Losing your recovery phrase, which nobody can give back to you
  • A mistake in this software, which is why the source is public

Five things worth doing today

Self-custody puts the work on you. It is not much work, and it is all front-loaded.

  1. Write the recovery phrase on paperNot in a photo, not in a password manager you also unlock on this device.
  2. Test it before you rely on itRestore into a second browser and confirm the address matches. Ten minutes now.
  3. Export an encrypted backupYour records live in this browser. If it is cleared they are gone, and the phrase does not bring them back.
  4. Keep the lock short if you trade in publicA till on a counter is a device strangers stand next to.
  5. Check the address before every first paymentThe wallet flags an address you have never sent to. Read that flag.