Skip to content

Security: beeswaxpat/scrib-desktop

Security

SECURITY.md

Security Policy

Scrib Desktop is an offline, encrypted text editor. We take reports about the encryption, file handling, and data integrity seriously.

Supported versions

Version Supported
1.10.x
1.9.x ⚠️ Critical fixes only
< 1.9

Reporting a vulnerability

Please do not open a public GitHub issue for security vulnerabilities.

Instead, use GitHub's private vulnerability reporting:

  1. Go to the Security tab of this repository.
  2. Click Report a vulnerability.
  3. Describe the issue, the affected version, and steps to reproduce.

If private reporting is unavailable, contact the maintainer through the contact details on https://scrib.cfd/.

We aim to acknowledge a report within 7 days and to provide a remediation plan or fix timeline within 30 days.

Scope and threat model

The user-facing list is the Threat model section of the README. This section names the adversaries so a reporter can tell which side of the line a finding falls on.

Defended against:

  • Someone with read access to your .scrb files but not the password. AES-256-CBC with HMAC-SHA256 (Encrypt-then-MAC), PBKDF2-SHA256 key derivation, and authenticated, self-describing KDF parameters (v3 format).
  • Someone who tampers with a .scrb. The HMAC covers the version byte, the KDF parameters, the IV, the salt, and the ciphertext, and it is verified with a constant-time compare before any decryption, so tampered ciphertext never reaches the unpadder.
  • A crafted .scrb header. The per-file PBKDF2 iteration count is range-checked before the KDF runs, capped at 2,000,000, so a hostile file cannot stall the app with an arbitrary work factor.
  • A crash or power loss during a save. Writes stage to a sibling file and land through an atomic rename, with .scrib-bak recovery on the next read.

Not defended against. These are limitations of the current design, not bugs, though concrete improvements to any of them are welcome:

  • Whoever supplied the note file you open. A .scrb, .rtf or .txt from someone else is untrusted input, parsed with no sandbox. Since 1.10.0 reads are capped at 64 MB and .rtf, table and image payloads are bounded, so a crafted note can no longer hang the app or exhaust memory, but the parsing itself is still unsandboxed and has no time budget. Scrib does enforce an http/https/mailto scheme allowlist on RTF import and again at link launch, restricts image embeds to data: URIs, and has no network stack at all. It does not apply that allowlist to rich text pasted from another application, or to links written back out into an exported .rtf, so an exported document can carry a link the note received from elsewhere.
  • Whoever can write to the folder holding your notes (a shared drive, a synced folder, removable media, a second local account). Scrib assumes that directory is yours: it stages writes at predictable sibling paths (<file>.scrib-tmp and <file>.scrib-bak), and because a save creates a new file and renames it into place, the note ends up with the permissions inherited from the folder rather than any per-file permissions you set.
  • Whoever controls the download. Release binaries are not code-signed, and the published SHA-256 is generated by the same workflow job that builds and uploads the zip, so it detects a corrupted download but not a compromised release. Build from source if you need stronger assurance.
  • Windows hibernation and paging. Passwords and decrypted note content are Dart Strings, which are immutable and cannot be zeroed. Hibernating or paging out writes that memory to hiberfil.sys / pagefile.sys, on the same disk as the notes and readable by the same attacker the first bullet above defends against. Full-disk encryption is the only real mitigation; auto-lock shortens the window. Locking a tab drops the references but cannot erase the strings. Locking also clears the clipboard when it still holds a slice of the note being locked, but Windows Clipboard History and Cloud Clipboard keep their own copies, which Scrib cannot reach.
  • A compromised machine (key-logger, RAM dump, attached debugger, a malicious build already running) and brute-forcing a weak password. Since 1.10.0 the strength meter accounts for common passwords, keyboard runs and repeated characters as well as length and character classes, so it no longer rates obvious dictionary passwords as strong. It is still a hint, not a check: PBKDF2 at 100,000 iterations raises the cost of an offline guess but does not make one infeasible.
  • Recovery of a plaintext file you later encrypted. Converting an existing .txt or .rtf writes the .scrb, then overwrites the original's bytes before removing it, and does the same to any .scrib-bak / .scrib-tmp sibling holding a copy (1.10.0 and later; earlier versions deleted without overwriting). Overwriting cannot guarantee the bytes are gone: on an SSD, a snapshotted volume, a backup, or a synced folder the pre-encryption copy may survive. For notes that must never exist in plaintext, create the note encrypted rather than converting one.
  • Filename and path disclosure. Recent files, the session snapshot, window geometry and preferences live in an unencrypted Hive database under %APPDATA%. Note contents are encrypted; their names and paths are not, and Hive appends rather than rewrites, so clearing recent files or the session does not immediately erase the earlier entries from that file.

Fixed security issues

  • 1.9.x: a save could mark a note clean against content that was never written. Every save path recorded the tab's live content when the write finished, not the content the write had started with. An encrypted save takes well over 100ms (isolate spawn, PBKDF2, two flushed writes), so anything typed during that window was marked saved while only the older bytes were on disk: no dirty marker, no prompt on quit, and no .scrib-bak to recover from. Each write now snapshots the content before it starts and marks the tab clean against that snapshot, so an edit made mid-write leaves the tab dirty and is persisted by the next save. The same snapshot is used for every routing decision, so tab state changing mid-write can no longer send ciphertext to a .txt or a rich-text envelope to a .rtf, and a tab locked while its save was in flight is no longer re-seeded with the decrypted note.
  • 1.9.x: an extension swap could replace an unrelated file with no prompt. Toggling encryption (Ctrl+E) or switching editor mode makes the manual save write a path the user never picked: notes.txt becomes notes.scrb, and the atomic rename replaces whatever was already at that destination without leaving a .scrib-bak. Each swap branch then deleted the source, so one Ctrl+S could destroy two files. Every swap now asks before replacing a different file, and it fails closed: with no confirmation available the save is refused rather than performed. Save As re-asks when it retargets the chosen path to .scrb, because the file picker's own replace prompt applied to a path that is no longer the destination.
  • 1.9.0: background saves could write plaintext over an encrypted .scrb. After toggling decryption on an open note (Ctrl+E), the auto-save, close-tab-save, and quit-save paths wrote the decrypted content back to the .scrb path, leaving the note unencrypted on disk. 1.9.0 makes every background save path refuse an encryption/extension mismatch; only the manual save performs the explicit extension swap. If you used Ctrl+E to decrypt a note in an earlier version and kept working with auto-save on, verify the file on disk is what you expect and re-encrypt it if needed.

A report that restates one of the "not defended against" bullets above (for example, "the password is recoverable from a memory dump") is an acknowledged limitation rather than a vulnerability. That list is deliberately specific, so anything it does not name is in scope: in particular, a concrete exploit against a hostile note file, a shared notes directory, or the release pipeline is worth reporting even though those adversaries are listed as undefended, because the bullets describe the current posture, not an intent to leave it there.

What to include in a report

  • The Scrib Desktop version and your OS version.
  • A minimal proof of concept or reproduction steps.
  • The impact you believe the issue has.
  • Whether the issue affects existing .scrb files on disk.

There aren't any published security advisories