I Built an Open-Source Alternative to OneTimeSecret - Here's How Blink Works
At some point, almost every developer, system administrator, or security engineer has had to send something they probably shouldn't send through a normal chat. A password. An API key. A database credential. A recovery code. A configuration file. A private document. The usual workflow looks something like this: "Hey, what's the password?" "Sure, I'll send it to you." โ Slack / Discord / Email โ "Thanks!" โ The secret stays in the conversation. The problem isn't necessarily that the communication channel is insecure. The problem is that the secret now has a lifetime much longer than it needs to have. That's what made me build Blink. Blink is an open-source secret-sharing platform designed around short-lived, self-destructing links. You can try it here: The source code is available on GitHub: https://github.com/MALTOisHERE/onlyonce The problem with sharing secrets Imagine you're working with another developer. You need to send them an API key. You open Slack and send: API_KEY=xxxxxxxxxxxxxxxx They copy it. Everything works. But the message is still there. Tomorrow, next month, or a year from now, someone who has access to that conversation may still be able to retrieve the credential. The same problem can happen with: - SSH credentials - database passwords - VPN configuration - cloud credentials - recovery codes - temporary credentials - private documents - internal configuration - sensitive notes Even if the communication channel itself is secure, permanent storage isn't always what you want. Sometimes you want: Send it โ let the recipient read it โ destroy it. That's the idea behind one-time secret sharing. Services such as OneTimeSecret have been built around this concept: sensitive information is shared through links designed to be used once and then disappear. I wanted to build my own implementation with a modern interface, an open-source codebase, and the ability to self-host. That's where Blink came from. What is Blink? Blink is a web application for sharing sensitive information through temporary links. The basic workflow is simple: CREATE Secret โ โผ โโโโโโโโโโโโโโโ โ Blink โ โโโโโโโโฌโโโโโโโ โ โผ Temporary URL โ โผ SHARE โ โผ Recipient โ โผ READ โ โผ DESTROY Instead of putting the secret directly into a permanent conversation, you create a temporary link. The recipient opens it. The secret is retrieved. After the configured conditions are met, it is no longer available. The goal is deliberately simple: Share something sensitive without leaving it sitting around forever. Why build another secret-sharing service? There are already several solutions for this problem. So the obvious question is: Why build another one? For me, it came down to a few things. I wanted something that was: - simple to use - open source - self-hostable - focused on ephemeral information - useful for both text and files - easy to deploy - transparent about its security model I also wanted to use the project as an opportunity to explore the engineering challenges behind ephemeral data. Because: "Delete this after someone reads it." sounds simple. It isn't always simple. The architecture At a high level, Blink consists of several components: โโโโโโโโโโโโโโโโโโโ โ Browser โ โ โ โ Create Secret โ โโโโโโโโโโฌโโโโโโโโโ โ โผ โโโโโโโโโโโโโโโโโโโ โ Blink API โ โ โ โ Secret handling โ โโโโโโโโโโฌโโโโโโโโโ โ โผ โโโโโโโโโโโโโโโโโโโ โ Storage โ โ โ โ Temporary data โ โโโโโโโโโโโโโโโโโโโ The frontend is responsible for interacting with the user. The backend handles the application's business logic and secret lifecycle. The storage layer holds the data required by the application until the secret expires or is consumed. The exact implementation is available in the open-source repository: https://github.com/MALTOisHERE/onlyonce Encryption Encryption is one of the most important parts of a project like Blink. Simply saying: "We use AES-256." isn't enough to explain whether a system is secure. The important questions are: - Where is encryption performed? - Where is the encryption key generated? - Where does the key live? - Does the backend ever see plaintext? - What exactly gets stored? - How is the recipient able to decrypt the data? - What happens if the database is compromised? - What happens if the application server is compromised? These questions are much more important than simply naming an encryption algorithm. Blink's encryption flow This section should describe the exact implementation used by Blink. For example, if encryption happens in the browser, the architecture could look like: USER SECRET โ โผ โโโโโโโโโโโโโโโ โ Browser โ โ โ โ Encrypt โ โ Generate keyโ โโโโโโโโฌโโโโโโโ โ โ ciphertext โผ โโโโโโโโโโโโโโโ โ Blink โ โ API โ โโโโโโโโฌโโโโโโโ โ โผ โโโโโโโโโโโโโโโ โ Storage โ โ โ โ ciphertext โ โโโโโโโโโโโโโโโ The important part is being completely transparent about what Blink's server can and cannot see. This is also one of the reasons I made the project open source. Security shouldn't depend solely on: "Trust me, it works." The implementation should be available for people to inspect. Secret lifecycle A secret shouldn't exist forever. That's the whole point. The lifecycle is roughly: CREATE โ โผ STORE โ โผ WAIT โ โโโโโโโโโโโโโโโโโ โ โ โผ โผ EXPIRED VIEWED โ โ โโโโโโโโโฌโโโโโโโโ โผ DESTROY Depending on the configuration, a secret can become unavailable because: - The recipient has already accessed it. - The expiration time has been reached. - The secret has otherwise been invalidated. The important property is that the secret has a finite lifetime. The interesting engineering problem: deletion "Delete the secret after it is viewed." Sounds easy. But what happens if two people open the same link at almost exactly the same time? For example: Secret โ โโโโโโโโโดโโโโโโโโ โ โ โผ โผ Request A Request B โ โ โผ โผ Read Read If the application isn't designed correctly, both requests might succeed. That means the secret wasn't really "one-time." This is one of the reasons ephemeral applications need to think carefully about: - atomic operations - concurrency - race conditions - transaction boundaries - cache behavior - database consistency - deletion timing A security feature isn't really a security feature if its implementation can be bypassed under normal concurrent access. Files make things more complicated Sharing text is relatively straightforward. Files introduce another dimension. A file may be: Password.txt backup.zip .env database.sql certificate.pem configuration.json Now the system has to consider: - file size - upload handling - temporary storage - download authorization - expiration - deletion - object storage - metadata - caching - access control A temporary file needs to follow the same lifecycle as a temporary text secret. If the application says: "This file expires in 10 minutes." then the underlying storage shouldn't accidentally keep an accessible copy forever. This is an important distinction between application-level deletion and actual data lifecycle management. Threat model One of the things I want to be very clear about with Blink is that no security system protects against everything. A useful threat model asks: What are we actually trying to protect against? For example: | Threat | Goal | |---|---| | Secret remaining in chat history | Prevent | | Secret remaining indefinitely on the platform | Prevent | | Expired link being used normally | Prevent | | Unauthorized access to a secret | Depends on implementation | | Database compromise | Depends on encryption architecture | | Server compromise | Depends on encryption architecture | | Recipient taking a screenshot | Cannot prevent | | Recipient copying the secret | Cannot prevent | | Compromised recipient device | Cannot prevent | | Malicious browser extensions | Cannot prevent | That last part is important. If someone gives a secret to another person, you cannot make the recipient unsee or copy it. Blink can control the lifetime of the link. It cannot control what the recipient does after seeing the information. Why open source? Blink is open source because I believe security-related software benefits from transparency. Anyone should be able to: - inspect the source - understand the architecture - run their own instance - identify bugs - propose improvements - contribute - challenge the security assumptions The repository is available here: https://github.com/MALTOisHERE/onlyonce If you find a security issue, please report it responsibly rather than publicly exposing an active vulnerability. Self-hosting One of the goals of Blink is that you shouldn't have to trust my hosted instance if you don't want to. That's one of the biggest advantages of open-source infrastructure. You can run the software yourself and control: - the infrastructure - the domain - the storage - the deployment - the logs - the network - the operational environment This is especially useful for teams that don't want sensitive information passing through a third-party hosted service. The self-hosting experience is also something I want to keep improving. What I learned building Blink The biggest lesson wasn't about encryption. It was that ephemeral data is surprisingly difficult to make truly ephemeral. You have to think about the entire lifecycle: Input โ Encryption โ Transmission โ Storage โ Retrieval โ Decryption โ Expiration โ Deletion โ Backups / Logs / Caches Deleting a database row doesn't necessarily mean every trace of the data has disappeared. You have to understand your entire infrastructure. That's one of the areas I'm continuing to explore with Blink. What's next? Blink is still evolving. Some areas I'm interested in improving include: - better self-hosting documentation - stronger security documentation - more deployment options - improved file handling - additional integrations - API support - better observability - security reviews - community contributions I'd also like to see people challenge the project's assumptions. If you are a security engineer, developer, privacy enthusiast, or self-hosting enthusiast, I'd
Comments
No comments yet. Start the discussion.