🔒 End-to-end encrypted
Payment methods are encrypted on your device with AES-256-GCM before upload. BoxOwl infrastructure cannot read them.

How it works in one paragraph

When you save a payment method, the card number and full metadata are encrypted on your phone with a key derived from your vault passphrase (or a registered passkey). The encrypted blob is what gets uploaded. BoxOwl servers can read a small set of display hints — the card network logo, the last 4 digits, the expiry, the cardholder name — so the card list renders without decryption. Everything else is opaque to us. CVV is never stored; the extension prompts for it at the moment of checkout and discards it after.

1. Add a card on Android

  1. Open Vault > Payment Methods.
  2. Tap the floating + button.
  3. Fill in the card number, expiry, cardholder name, and billing address (you can pick an existing address from your vault).
  4. Tap Save. If this is your first encrypted entry, the app walks you through vault setup: pick a passphrase (12+ chars) and write down the 12-word BIP-39 recovery phrase. The recovery phrase is shown once — BoxOwl servers never see it.
  5. After confirmation, the card appears in the list with its network icon and last-4. Tap to view masked PAN; re-authentication (biometric or passphrase) is required to reveal the full number.

The same passphrase works across the Android app and the browser extension. Set it up once; both clients derive the same key.

2. Add a card from the extension

  1. Open the BoxOwl popup and tap Save PasswordPayment Method (or use Fill Payment on a checkout page and choose Save new card).
  2. Enter the card number (Luhn-validated), expiry MM/YY, cardholder name, and pick a billing address.
  3. Unlock your vault if it isn't already. The popup encrypts the PAN + metadata using AES-256-GCM with a per-entry data key, then wraps that key with your vault key (Argon2id-derived).
  4. The opaque ciphertext is POSTed to BoxOwl. Display hints (last-4, network, expiry, cardholder name) are sent in clear so the card list works without a re-decrypt.

3. Checkout autofill

On a checkout page:

  1. The extension detects payment fields (cc-number, cc-exp, cc-csc, plus regex fallbacks for sites that don't use the standards).
  2. You pick a card from the popup. If the vault is locked, the extension prompts for biometric (passkey) or passphrase unlock first.
  3. The background service-worker fetches the ciphertext, decrypts it locally, and injects the PAN, expiry, and cardholder name into the form. CVV is shown as a transient prompt — you type it in, the extension auto-fills, and the value is discarded immediately.

The unlock prompt UX is one round-trip: once the vault is unlocked in this browser session, subsequent card fills don't re-prompt for 15 minutes of activity (the timer resets on each use).

What BoxOwl can and can't see

FieldVisible to BoxOwl?Where it lives
Full card number (PAN)NoInside the encrypted ciphertext blob
CVV / CVCNoNever stored anywhere — transient at checkout
Cardholder nameYes (display hint)Plain column
Last 4 digitsYes (display hint)Plain column
Expiry month/yearYes (display hint)Plain column
Card network (Visa, MC, etc.)Yes (display hint)Plain column — derived client-side from BIN
Billing addressYes — same as your other vault addressesLinked by ID; the address itself follows your visibility settings

The display hints are deliberate: they let the card-list UI render with a network logo and "•••• 1234" line without decrypting. Showing the full number requires unlock + decrypt.

Crypto details

The same primitives back passwords and secure notes — they share shared/e2ee-constants.ts between the extension, Android app, and backend so all three agree on byte layout. See the trust page for the broader picture.

PCI scope

BoxOwl's posture is that we are out of PCI-DSS scope for the card-storage feature because BoxOwl never receives, processes, or stores raw cardholder data — only opaque ciphertext we cannot decrypt. The user's device is the cardholder-data environment.

This is the same legal argument that applies to fully end-to-end encrypted password managers: the operator demonstrably cannot read the protected data, so they're not a CDE participant. We are not a payment processor and do not charge cards on your behalf — that role is handled by Stripe for subscription payments (separate from the vault).

If your organization needs a PCI attestation specifically for BoxOwl-stored cards, contact us via trust.html — we can provide the design doc, threat model, and crypto artifacts that support the out-of-scope argument.

Rotating your vault passphrase

From the Android password list, open the overflow menu and choose Change passphrase. The flow:

  1. Enter your current passphrase to derive the current KEK.
  2. Enter a new passphrase. The app derives a new KEK with the same Argon2id params and per-user salt.
  3. Locally, the app fetches every encrypted DEK (passwords, payment methods, secure notes, TOTP), unwraps with the old KEK, re-wraps with the new KEK, and POSTs the batch atomically to /vault/passphrase/rotate.
  4. You're shown a new BIP-39 recovery phrase. Write it down — the old one is invalidated.
  5. Biometric/passkey enrolment is cleared. You'll re-enrol on the unlock screen so the device-bound key wraps the new KEK.

Card data itself is never re-encrypted during rotation — only the wrapping DEK changes. That keeps rotation fast and avoids re-uploading large ciphertext blobs.

Limitations & what's next

Related

← Back to Docs