blueloop4622 downloadsEncrypt inline secrets in Markdown notes; copy mixed selections as plaintext.
⚠️ Use at your own risk
- No password recovery. Your password is never stored anywhere. Lose it and your encrypted secrets are gone permanently.
- No security audit. This plugin has not been reviewed by a cryptographer. Do not rely on it to protect high-value secrets.
- No stability guarantee. This is early software. Keep backups of any note containing encrypted spans.
An Obsidian plugin for encrypting inline secrets inside Markdown notes.
A note stays ordinary plaintext — except for chosen values, which are stored as
encrypted inline tokens. After unlocking a note once with a master password, you
can select any region (ordinary text + N secrets) and press Ctrl/Cmd+C once
to get the full decrypted plaintext on the clipboard. The .md file on disk
always contains only ciphertext.
text + secretA + text + secretB, one Ctrl/Cmd+C → clipboard has the full plaintext. No ciphertext ever reaches the clipboard..md file. Plaintext lives only in memory until you lock or close Obsidian.Always use Insert secret at cursor when adding a new secret. This is the safest approach: the secret value is typed directly into a modal and goes straight to ciphertext — the note body never sees the plaintext, so Obsidian's autosave, sync, and File Recovery cannot capture it.
All commands are available from two places:
| Command | When to use |
|---|---|
| Insert secret at cursor | Add a new secret safely — plaintext never touches the document |
| Encrypt selection | Encrypt already-typed text into a secret token (see sync risk below) |
| Unlock current note | Prompt for password; decrypt all secrets into memory |
| Lock current note | Clear decrypted state; all secrets re-lock to 🔒 |
| Edit secret at cursor | Change an existing secret value; note must be unlocked, cursor on the token |
Assign these in Settings → Hotkeys (search "SecretSpans"):
| Command | Suggested hotkey |
|---|---|
| Insert secret at cursor | Ctrl/Cmd+Shift+I |
| Encrypt selection | Ctrl/Cmd+Shift+E |
| Unlock current note | Ctrl/Cmd+Shift+U |
| Lock current note | Ctrl/Cmd+Shift+L |
Password consistency. All secrets in a note must use the same password. If you try to insert or encrypt using a password that does not match the existing secrets, the operation is blocked with a notice. Unlock the note first to verify the correct password.
Auto-lock on insert. When you insert or encrypt a new secret into an already-unlocked note, the plugin automatically locks the note before writing the token. This keeps the display consistent (all secrets show as 🔒) rather than mixing unlocked and locked. Unlock the note again to see all secrets together.
Edit secret preconditions. Edit secret at cursor requires the note to be unlocked AND the cursor placed on an existing secret token. If the note is locked, unlock it first. If the cursor is not on a token, move it onto one and try again.
localStorage.`secretlock:v1:<base64(salt[16] | iv[12] | ciphertext+GCM-tag)>`
Your password is the only protection for your secrets. Use a long random passphrase
(4+ words) or a password generated by a password manager. A weak password can be
brute-forced offline by anyone who obtains your .md files — the encryption does
not prevent guessing, it only makes it slow.
There is no recovery path. If you forget your password, your secrets are gone. Store the password in a password manager, not in another note.
Obsidian may save and sync your note before you encrypt.
When you type a secret value into a note body and then run Encrypt selection, there is a window — even if only a few seconds — during which Obsidian has already auto-saved the plaintext to disk and potentially uploaded it to cloud sync. Use Insert secret at cursor to avoid this entirely.
| Source | Risk |
|---|---|
| Obsidian Sync / iCloud / Dropbox / Git | The plaintext version of the note may be uploaded before you encrypt. Check your sync provider's version history and delete any plaintext snapshots after encrypting. |
| Obsidian File Recovery plugin (core, on by default) | Snapshots the note periodically. A snapshot taken between typing and encrypting will contain plaintext. Find snapshots at Settings → File recovery and verify none predate your encryption. |
| Editor undo history | After encrypting, pressing Ctrl/Cmd+Z will undo the encryption and restore the plaintext. The note is in plaintext until you encrypt again or close without saving. |
Keep regular backups of your vault. Encrypted tokens are unrecoverable without the correct password — a corrupted token cannot be repaired. Backups protect against accidental deletion and file corruption, not against password loss.
git clone https://github.com/blueloop46/secret-spans
cd secret-spans
npm install
npm run build
Copy main.js, manifest.json, and styles.css into your vault's
.obsidian/plugins/secret-spans/ folder, then enable the plugin in
Settings → Community plugins.
npm test
Runs unit tests for the pure core (format, substitute, crypto) — no Obsidian runtime needed.
src/
main.ts # Plugin entry: commands, context menu, owns unlock state
format.ts # TOKEN_RE, tokenRegex(), parseTokens, isToken — pure
crypto.ts # encrypt / decrypt — pure, Web Crypto
substitute.ts # substituteTokens — pure, the copy core
unlockState.ts # Per-file plaintext cache; unlock / lock / lockAll
livePreview.ts # CM6 decorations + copy handler
readingView.ts # Markdown post-processor + copy handler
ui.ts # PasswordModal, InsertSecretModal, EditSecretModal
test/
substitute.test.ts
crypto.test.ts
crypto.fuzz.test.ts
ARCHITECTURE.md # Architecture decisions and module map
See ARCHITECTURE.md for architecture decisions and module responsibilities.