I’m Akshaj Rawat , and I’ve been working on a proposal to bring Local Note Encryption : Idea no. 7 to Joplin. This feature allows users to protect sensitive notes with a local-only password that never leaves the device.
AkshajRawatIdea7Proposal-V2.pdf (509 KB)
AkshajRawatIdea7Proposal-V3.pdf (512.3 KB)
AkshajRawatIdea7Proposal-V4.pdf (860.7 KB)
AkshajRawatIdea7Proposal-V5.pdf (864.7 KB) (LATEST)
1 Like
I had a skim read of your proposal and I think the solution sounds feasible. FYI proposal number 7 has just been updated to optionally include encrypted notebooks as well. I’m interested to know if you have ideas for how that could be implemented and how much project time it would add
I went through the code for encrypting the notebook and I think most of the part is same as encrypting the notes, like intercepting the load and save pipeline.
Also there will be some edge cases like one I came across is if we move a note to an encrypted notebook it should get encrypt too etc.
I will need some time to look through the approach and update the proposal. I will do it and let you know.
1 Like
Also you might need to extend your proposal with more details about resource encryption/decryption. I think there are many ways to approach this particular issue with pros and cons in terms of performance and security, so you might want to look into this in advance
1 Like
Do I understand it correctly that note password is not going to be stored anywhere, even in OS credential manager and user is prompted for the password each time the note is opened?
@executed Based on the implementation proposal which was posted, I think it is fair to assume you would get a prompt every time. While that would be acceptable for individual notes, this behaviour would need to be reconsidered for encrypted notebooks, as it is not ideal to have to enter your password for every note you open within an encrypted notebook
1 Like
I am very happy to learn about this proposal
and the fact that whole encrypted notebooks, not just individually encrypted notes, are being considered. Hopefully on both Desktop and Mobile.
Please also consider that notes inside an encrypted notebook will likely have internal links to each other and the ui should let the user navigate from one note to the next via internal links without prompting for the password at every internal link.
4 Likes
got it! Looking through it too
1 Like
I have spent the last few days researching the architecture for these edge cases and have completely updated my proposal to cover them.
Here are the major additions to the new proposal PDF:
-
Notebook Encryption : I've mapped out the architecture for locking a Folder, which will trigger a recursive LocalEncryption function to safely encrypt all nested notes and sub-folders.
-
Resource (Attachment) Encryption: To balance security with Electron's memory constraints (preventing OOM crashes from large PDFs), I have outlined a "Secure Temp Cache" approach. This will decrypt physical files to an OS-level .tmp location for UI rendering, utilizing strict try/finally blocks to guarantee the plaintext is destroyed immediately after use.
-
Seamless Session Management: I expanded on how the UI will allow users to navigate between internal links without being prompted for a password on every click, utilizing RAM-only EncryptionService state.
My new PoC branch and Proposal :-
Draft proposal: AkshajRawat GSoC 2026 proposal for Joplin.pdf (828.0 KB)
Let me know if you have any questions about the Resource or Folder architectures!
@akshajrawat I haven’t had a look at the new proposal yet, but as it’s not mentioned in your summary, just wondering did you implement anything to handle remembering the password temporarily when opening consecutive notes within an encrypted notebook, and also when navigating through note links?
Also given that notes are decrypted JIT into memory, will entire notebooks be decrypted recursively upon unlocking the notebook, or just per note as they are opened? If decrypting the entire notebook into memory, I would have concerns about being able to get an out of memory error. You would need to at least decrypt the titles and maybe some metadata of notes in one go though, in order to be able to see the note titles for navigation
Actually, the password is not remembered at all making this more secure, once the user enter the password the
await EncryptionService.instance().loadMasterKey(masterKey, password, false);
runs and loads the master key in the RAM. So, now we can just do
await encryptionService.decryptString(note.local_cipher_text, {
masterKeyId: note.local_master_key_id,
})
in Note.load function to decrypt the body.
Also for OOM query, no the whole childrens of notebook are not decrypted in the RAM since joplin already follow lazy load of note I have utilized the current architecture and only place where the body decryption take place for note is the Note.load function which runs when the note becomes active.
Initially in notebook the title will not be encrypted as the user should know what he is opening and.. once the notebook is open I will utilize the already written note.previewFields function which does not provide 'body' and 'local_cipher_text' so we can seamlessly show the sidebar of notebook with the notes title without ever loading the 'body' or 'local_cipher_text'
Once a note is clicked it becomes active note which is an already implemented feature of joplin and then my updated Note.load funtion runs to decrypt the body per note click.
ALSO.. Note.load never converts the 'local_cipher_text' to body it only decrypts the body and give the decrypted string to frontend..
So, once the active note is changed the old note content is safe again since the body field is still empty in the database..
Hope this clears your query!!
1 Like
If possible I think it would be worth considering a plugin for this project?
I see it intends to intercepts Note.save() / Note.load() which means it will affect pretty much everything in Joplin - loading, saving notes, sync, E2EE, sharing, search, data API. It would also need to work on desktop, mobile and CLI. And because notes, notebooks and resources will sometimes be encrypted, it will most likely affect plugins and external apps too. How about the web clipper? If the user selects a notebook as a target and that notebook is encrypted I guess there should be a UI to enter the password? And UI is another thing that would need to be implemented on all platforms.
Would Joplin Server be affected?
How about search? If a note is currently open and the search engine runs, we should make sure it doesn't end up indexing the plain text. Same for the revision service, but also any plugin or external app that can access Joplin's data. We should also ensure that no plugin or external app is broken by this change.
Resource management will have be changed - now we display the resources right away because they are there on the disk. But how to handle this with encryption? Let's say you have a note with 20 PDFs of 1GB each - you aren't going to decrypt all this when the note is opened, which means it will be when opening the resource, and that's more UI to implement for all the editors.
Those are just a few edge cases that come to mind and I'm sure we'll keep finding more.
That's why it may be wise to consider the scope of this project carefully, and perhaps consider a plugin that can have a more restricted scope and that could be written in a way that doesn't affect pretty much everything.
Thank you for taking the time to review the architecture!
You are completely right about the massive effect it creates across the Revision Service, Search Indexer, Web Clipper, and 1GB resource attachments. Modifying the core Note.save() pipeline is simply too risky for a 12-week timeline.
I am actually really excited about this change, but I wanted to do a quick check on the timeline. Given that the final GSoC submission deadline is March 16th, I want to make sure I am aligning perfectly with your expectations.
If that is the direction you'd like to see for this idea, I will dive into the Plugin API documentation right now. My first goal will be figuring out if the current hooks can temporarily hide the standard editors when an encrypted note is selected. If the API doesn't currently support that level of UI control, I will explicitly include "extending the core Plugin API to support editor hiding" as part of my new GSoC project scope.
Thanks!
Just to be clear I'm not suggesting it needs to be done one way or the other. I could be wrong too, and if you find that there's a way to implement this in a safe, controlled way then why not. Or it could be a plugin, or an external app. It's worth thinking outside the box.
As for the deadline, proposal submission phase opens on 16 March, and you have till end of March to finalise and submit your proposal
If you wanted the implementation as a plugin, we already have a recent plugin for encrypted notes Joplin Plugins - Secure Notes , which works on both desktop and mobile.
I’ve been supportive of this as a GSoC project as I was hoping for something built into Joplin, as being part of the core code guarantees ongoing maintenance. Or are you suggesting it could be a default plugin included with Joplin?
The secure notes plugin does raise an additional point about this project though, which I don’t think has been considered by the proposal. I have been working closely with the developer of the plugin, in order to address some issues due to restrictions in the core Joplin code, and have submitted and merged core Joplin PRs to address those restrictions.
The main things which needed to be addressed for the plugin was that note history contains unencrypted data after encrypting note contents, which makes note encryption somewhat pointless if note history is enabled. The plugin prospectively (as it is awaiting the Joplin 3.6 release) will delete all revisions for a note upon encryption and decryption (these are handled by manual toggles). This is a somewhat minimal solution to solve the issue, but ideally note revisions should be encrypted rather than being deleted. If we wanted to go down the plugin route, for an improved experience we likely would need to implement more core Joplin changes as well, to enable functionality like encrypting / decrypting all revisions for a note in an efficient manner (and which is protected from race conditions with the revision service), and these functions would be to be exposed publically as well.
I guess one key thing the secure note plugin does not currently support is editing an encrypted note without decrypting the full note contents in the database, which therefore syncs the unencrypted contents back to the server until re-encrypted. This can be solved using the editor api, but you essentially have to either write your own editor (which will be bear bones and limits the editing capability while encrypted), or you extend the editor API to allow embedding the full Markdown and Rich text editor, if that’s possible
@akshajrawat Ideally titles would be encrypted also for a feature complete encrypted notebook, but I guess it’s not essential. Regarding password remembering though, it is going to be an inconvenient experience if you have to enter the password every time you follow a note link of an encrypted note, or open individual notes within an encrypted notebook. It doesn’t really feel like an encrypted notebook feature if every note in the notebook is treated like an individually encrypted note, rather than the notebook being encrypted as a whole. Remembering the password for a configurable time eg. 5 minutes (or until closing the app) would be a suitable solution though.
I see it intends to intercepts Note.save() / Note.load() which means it will affect pretty much everything in Joplin
@akshajrawat Can’t you just wrap the encryption / decryption logic around the usages of Note save and load in the editor / viewers in Joplin instead, where a note is marked as encrypted? Doing this wont include encrypted note support for the cli app or the rest / plugin apis, but I don’t think that’s so much of an issue, as there main use case would be for the desktop and mobile apps, and it might be a safer approach overall
I think there has been some problem while conveying what I wanted to say in my last comment...
Yes you dont have to enter the password each time, because password is only used to load the local master key to the RAM , so once you promt the password the RAM holds the local master key and till then every locked note/notebook will be unlocked (this means they will not show the password promt each time you go to a new notebook or note)
Here, Unlocked does not means all the ciphered text is decrypted , its just that the app now knows that the user who is using entered the password and will be able to view each locked note and notebook. So basically you have access to all locked vault but the data is still in its encrypted form until the decryption happen i.e , when the user clicks on a certain note/notebook and joplin make it active .
Also, as I mentioned earlier the app does not ever move local_cipher_text text back to body column unless the note is set to is_locally_encrypted = 0 (false).
1 Like