Security Issue: Incomplete E2E Encryption Verification

The Real Problem I Found

I started this weekend trying to build a command-line sync client (which may or may not even be possible), but I’ve stumbled onto what I think is a more important security issue.

We can’t actually verify Obsidian’s complete end-to-end encryption - only part of it.

What I Discovered

Following the E2E encryption verification docs, I can successfully verify WebSocket data encryption using the published scrypt parameters. Great!

But the /vault/access API endpoint uses a completely different authentication method that’s undocumented. Same password, same salt, different hash entirely.

Why This Matters for Security

If part of the encryption chain is opaque, then the “verifiable encryption” promise isn’t complete. We can verify data encryption but not API authentication - leaving a gap where we have to trust rather than verify.

For true end-to-end verification, users should be able to independently audit every step of the authentication and encryption process.

The Security Questions This Raises

Without documentation, I can’t rule out concerning possibilities:

  • Is the API using weaker parameters?
  • Different algorithms?
  • Password hashes instead of derived keys? (Probably not, but I can’t verify that)

I’m sure Obsidian is following best practices - they’ve done security audits and clearly understand encryption. But the opacity means users can’t verify it themselves.

What Should Happen

The E2E verification documentation should cover the complete authentication flow, not just data encryption. If Obsidian believes in verifiable encryption (which they clearly do), then every component should be verifiable.

Technical Details

# This works for WebSocket data verification
key = hashlib.scrypt(password.encode('utf-8'), salt.encode('utf-8'), 
                    n=32768, r=8, p=1, dklen=32)
# But API authentication uses something completely different

TL;DR: Started building a sync client, found a gap in security verification that affects all users who want to audit Obsidian’s encryption claims.

Has anyone else noticed this discrepancy?

I’m looking at the server side for the API and we’re simply comparing the hash with what is stored in the DB. I’m pretty sure the websocket verification uses the same hash because the sync server just calls to the API server for the same verification.

What do you mean by “uses a completely different authentication”? Are you passing your login/auth token correctly?

But IIRC the hash is simply to verify that you have the correct key, to prevent clients from sending up file data that is encrypted with the wrong key and thus messing up the vault data. The API server doesn’t handle any actual data or encryption.

The other thing is, we purposefully don’t have APIs published and discourage third party sync clients, because we are unable to quality control and prevent undefined behavior when third party sync clients misbehave. It’s easy to get the encryption details wrong and end up with corrupted or deleted files, introduce errors to the sync process and interrupting sync for the Sync plugin, or possibly trigger infinite loops that overflows the user’s storage, or worse, causes an unintended DoS attack on the sync server.

I figured out the issue, I was largely being dumb!

But I appreciate your time.

For the most part, I’d really just like to build a download client that runs in a terminal, something I can integrate into my existing backup process.

I do appreciate your concerns though, but I think obsidian is generally used by people who like to tinker under the hood and an API is always going to be a curiosity to explore.

I’m guessing there are no plans on the horizon for library that would alleviate those concerns though…

1 Like

Yeah not at the moment. I think it shouldn’t be a problem if you are just tinkering for your own use case, as long as you aren’t planning to publicly distribute such a solution and you are using it with your own remote vault. And please please make sure your scripts have appropriate error handling and back-off mechanisms so you don’t DoS our servers on a loop.