I’m not a security expert, so I spent a few hours today looking into this. You said “Browsers encrypt the IndexedDB storage file themselves, so that should not be a weak link.” But I can’t find any evidence of that, everything I read says that IndexedDB is not encrypted by the browser. Where would it store the key? See e.g. the comments on this page.
I looked at the IndexedDB sqlite file in my Firefox 89 profile folder, and it does indeed contain the unencrypted ascii text of my Moo.do documents. It’s a little scrambled, but I could easily read it with a hex editor or sqlite browser. After I logged out and quit the browser, the IDB files were still there. Most of the text had been cleared out, though there was at least one sentence from one of my documents, and some other information. Similarly, in the desktop app’s .Idb files, I could read the unencrypted text of my documents. In this case though, when I logged out and quit the app, the entire text remained in the files, it was not cleared.
I’d say this is a weak link in some circumstances, since Moo.do leaks its data onto the hard drive in an unencrypted plain-text form. Simply deleting or clearing a text or sqlite file isn’t sufficient to destroy the data. For example, another user attempting to recover a file they deleted using off-the-shelf recovery software may inadvertently discover parts of old Moo.do documents, and this could happen on any shared computer at home or at work. In some systems, an SSD with TRIM reduces the chances of erased text being recovered, but not 100% - especially in higher-risk situations like a border search or seizure of a laptop or phone. In the case of the desktop app, the text isn’t even deleted on logout - the app leaves unencrypted copies of the Moo.do documents behind, that anyone can easily find and read with a hex editor.
You mention that “the generated encryption key is stored in IndexedDB, where it is secure and cannot be exported.” I guess this means you’re using the CryptoKey API. But the “cannot be exported” only applies to exporting via javascript in the browser. If someone has access to the IDB file on disk, the key can also easily be read out. See this presentation. Posession of the key would require the Moo.do login password to access documents in the cloud, but this could be requested by law enforcement, defeating the zero-knowledge encryption.
Some of these issues aren’t exclusive to Moo.do. If you’re storing a persistent private key on a user’s device for convenience, there are going to be tradeoffs. One option, if possible, might be to store only encrypted data in IDB, rather than the unencrypted plain text, and an option to store the key only in RAM. That could improve the security at the cost of having to enter the encryption password every browser restart. If you’re advertising “extreme privacy”, maybe an independent security audit would be valuable. To be honest, given the disparity between what you wrote about the security of the IDB storage, and what I found out myself, plus Mozilla’s warning about using the crypto API, I have to wonder if there are other parts of Moo.do’s privacy chain that have weak links. One related thing I noticed is that in the desktop app, “Enable automatic backups” seems to be checked by default when you install it. You might want to not do that. When you check “encrypt local files”, how is the key derived, and is it also stored unencrypted in IDB? An option to automatically log out when you quit the desktop app might also be helpful in a work environment.
Having said all this, I’m still going to prefer Moo.do over Dynalist or the others, where the documents are stored in the cloud without any encryption, and open to employees, hackers, or government requests to read. But I’m not going to log in to my Moo.do account on a work computer, due to the data leakage, and I’d feel better if unencrypted copies of my documents and encryption key weren’t cached in the browser or desktop app even on my own machine.