Link Sharing: How we built secure credential sharing without seeing your data

At work, you need to share a password with a contractor. Or, at home, you need to send Wi-Fi credentials to a visiting guest.
You know that they’re not using Dashlane, and you struggle to copy the username and password into Slack, email, or a text message. You know it's insecure. The password sits in chat logs and email archives indefinitely. And you may wonder, what's the alternative?
Our customers told us this gap was pushing them toward insecure workarounds. That’s why we built Link Sharing. Link Sharing generates a temporary link that our users can send via email or a direct message to share a password with someone who doesn’t have a Dashlane account. No account required or app to install.
Dashlane servers must never see the shared credential, not even in transit.
This post explains how we achieved using client-side encryption, URL fragments, and how we defined the threat model and defined appropriate security measures. If you're an engineer who cares about applied cryptography, or a security-conscious user who wants to understand what "zero-knowledge" actually means in practice, please read on.
TL;DR: The security guarantees
Bottom line before entering the deep dive:
- Your credentials are encrypted on your device before they leave it. The decryption key lives only in the URL you share, and Dashlane servers never see it.
- Even if Dashlane’s infrastructure were compromised, attackers would get only encrypted blobs.
- Dashlane employees cannot read your shared credentials.
The challenge: sharing without an account
Traditional Dashlane sharing works between authenticated users. Both parties have Dashlane accounts, encrypted vaults, and established device trust. The cryptographic handshake happens between known entities.
Link Sharing breaks this model entirely. Your recipient:
- Doesn't have a Dashlane account
- Doesn't have the Dashlane app or extension installed
- Accesses the credential via a web browser
- Receives a single, self-contained URL that grants complete access
The insecure approach would be to store credentials on the server infrastructure and serve them to anyone with the right link. This would mean that the server has access to the shared credentials. This breaks the zero-knowledge architecture and is not acceptable.
The solution: encryption key in the URL fragment
Our architecture rests on a simple and yet powerful principle: the key never reaches the server.
Anatomy of a Link Sharing URL
When you generate a sharing link, it looks like this:
https://share.dashlane.com/0c90af73-d077-43ca-9fc7-32a74cfa79cc#6f642db043b3bf775294772516785686ba93371a5cd592b600e1b857f4...
Let's break it down:
| Component | Value | Purpose |
| Domain | share.dashlane.com | Our landing page |
| Path | 0c90af73-d077-43ca-9fc7-32a74cfa79cc | Item UUID (server-generated identifier) |
| Fragment # | 6f642db0...04b31a | Encryption key (64 bytes, hex-encoded) |
The magic is in the fragment (everything after the #).
Why the fragment matters
Here's the critical requirement: URL fragments are never sent to servers.
The fragment identifier is processed entirely client-side. When your browser requests:
The HTTP request looks like:
The fragment is stripped. Our servers receive the UUID but never see the encryption key. The decryption key exists only in:
- The sender's device (when creating the link)
- The recipient's browser (when opening the link)
- Out of bounds transmission channels (email, slack…)
Implication: the confidentiality of the shared credential depends on the confidentiality of the link itself. If the link is forwarded, pasted into the wrong channel, logged by a third-party system, or intercepted, an attacker may be able to access the credential.
The encryption architecture
The encryption key: A 64-byte cryptographic secret
The encryption key is a 64-bytes secret, composed of two pieces: the encryption key and the hmac key:
We generate the encryption key using the Web Crypto API's cryptographically secure random number generator:
AES-256-CBC-HMAC: Authenticated Encryption
We use AES-256-CBC with HMAC-SHA256 for authenticated encryption. This provides:
- Confidentiality: AES-256-CBC encrypts the credential data
- Integrity: HMAC-SHA256 detects any tampering with the ciphertext
- Authenticity: Only someone with the encryption key can produce a valid MAC
The encryption flow (sender side)
The sender flow is straightforward: generate key → encrypt → upload blob → construct URL. At no point does the encryption key leave the client.
When the encrypted blob is uploaded, the server generates a UUID v4 that uniquely identifies the stored blob. This UUID appears in the URL path and is later used by the recipient to download the blob.
The decryption flow (recipient side)
On page load, the client extracts the encryption key from the URL fragment and splits it into the AES-256 encryption key and the HMAC-SHA256 key.
After a human check (based on Cloudflare Turnstile), it requests the encrypted payload by UUID, then recomputes and verifies the HMAC before attempting decryption.
If integrity checks pass, it decrypts the ciphertext using AES-CBC and parses the resulting plaintext credential.
The secret never leaves the browser: only the UUID and encrypted blob are ever sent over the network.
How we got here: Threat Modeling
In the Dashlane software development cycle, before writing production code, we conduct threat modeling. We identified 15 distinct threats across five categories: link transmission risks, server-side attacks, landing page attacks, cryptographic risks, and operational failures.
Some examples of what we considered:
| Threat | Our Response |
| Link leakage / disclosure | We treat this as a first-class threat. Mitigations: single-download (first accessor wins), 24h expiration (limits exposure window), abuse checks (Turnstile). Planned: recipient verification and manual revocation to enable safer longer-lived links. |
| S3 storage enumeration | Even with full S3 access, attackers get only encrypted blobs. UUID entropy avoids enumeration. |
| Landing page JavaScript compromise | CSP headers, strict code review |
| Weak random number generation | Use a CSPRNG (OS-entropy, unpredictable) for keys. Not regular PRNGs like Math.random(). We generate keys with crypto.getRandomValues. |
We identified additional hardening measures and corresponding mitigations, and we will introduce them progressively as defense-in-depth:
- Cryptographic metadata signatures: We evaluated signing metadata with AWS Nitro enclaves to detect tampering. E2E authenticated encryption protects both confidentiality and integrity of the data. On top of that, IAM policies and audit logging control and monitor access to the encrypted data.
- Subresource Integrity (SRI): Deferred due to build pipeline complexity. CSP provides the primary protection layer.
- Recipient 2FA / additional challenge: Intentionally excluded to keep the first version of the feature simple. The single-download limit and automatic expiration provide sufficient risk reduction. We plan to add recipient verification (e.g., 2FA/email) in a later iteration.
Documenting what we chose not to build, and why, is as important as documenting what we built. Future engineers need to understand the trade-offs, not rediscover them.
Time and download limits: defense in depth
Zero-knowledge encryption is our primary defense, but we layer additional controls:
These limits primarily mitigate link disclosure risk. Since possession of the link implies possession of the decryption key, we minimize the blast radius of a leaked link by reducing both time-at-risk and the number of successful accesses.
Time-Based Expiration
In our initial release, links expire after 24 hours with a single download allowed. We chose fixed limits to simplify the security model and gather real usage data. Configurable -longer- expiration and increased download limits are coming in future milestones.
Team Policy Enforcement
For enterprise customers, admins control whether Link Sharing is available. The feature requires linkSharing policy to be ON and internalSharingOnly to be OFF in the admin console. The server enforces this on both upload and download.
We validate at download time too: if an admin disables the feature while a link is active, existing links stop working immediately.
Why These Limits Matter
Even with correctly implemented encryption, limiting exposure windows reduces risk:
- Leaked links expire after the first access
- Forgotten links auto-expire
- Compromised channels have a limited impact
- Admin policy changes take effect immediately
Why not other approaches?
We evaluated several alternatives before landing on this architecture:
Why not asymmetric encryption (public/private keys)?
Recipients don't have Dashlane accounts, so they don't have key pairs. We'd need to generate keys on the landing page, but then we'd need to securely deliver the public key, which would bring a lot of friction in UX. So we’re back to symmetric encryption. The fragment-based approach is simpler and achieves the same security properties.
Why not just email the password directly?
Email is insecure by design. It is unencrypted in transit (often), logged by servers, archived indefinitely, and accessed from multiple devices. A time-limited, single-use link with E2EE is more secure. You may still be sending something (the link) over an insecure channel, but the damage from interception is bounded by the link's constraints.
Conclusion: Secure by Design
We chose a design that enforces zero-knowledge through its construction: the decryption key never touches our servers. Putting the encryption key in the URL fragment - never transmitted by browsers - lets us deliver link sharing without exposing plaintext or keys to our infrastructure.
Dashlane servers will never know:
- The domain of the shared item
- The username, password, or any other field
- The decryption key
This isn't a promise backed by policy but by design. Even with a court order, we couldn't decrypt your shared credentials, because only you hold the key.
While our current security model effectively mitigates identified threats, we continuously strive for enhancements. We acknowledge that the 24-hour time limit and single-download constraint are intentional, present-day controls to bound the impact of link disclosure.
Treat sharing links like passwords. Anyone with the link can view the credential once.
- Forwarding the link = forwarding the password.
- Only share with the intended person and over a channel you trust.
What's Next
This is our first release. Based on customer feedback, we're planning:
- Recipient verification: 2FA verification before access
- Configurable controls: expiration and max downloads
- Allow user manual revocation: Invalidate a link before it expires
- More shared item types: Beyond login credentials
- Mobile apps: Currently web extension only
We'll continue applying the same threat modeling rigor to each new capability.
Sign up to receive news and updates about Dashlane




