github akitaonrails/FrankMD v0.7.0

3 hours ago

v0.7.0

Released: 2026-07-24

Changes since v0.6.1 (8f6f69b..merge of #120#124). A batch of security and robustness fixes plus one UX feature, all from @samirhvbr, integrated with additional hardening.

Security

  • Path containment by ancestry, not string prefix (PR #120 by @samirhvbr): The traversal guards in NotesController#serve_asset, NotesService#safe_path, and ImagesService#safe_path are consolidated into one PathSafety.contain. It fixes a sibling-prefix bypass (base /data/notes no longer accepts /data/notes-backup/...), rejects absolute-path and ../ escapes, and — via a realpath re-check — rejects symlinks inside the tree that resolve outside it. Behavior note: notes that are symlinks pointing outside the notes directory are now treated as out-of-bounds and can't be read/served; keep note content inside NOTES_PATH.

  • Enforce the image allow-list on base64 uploads (PR #121 by @samirhvbr): The base64/AI-image upload path (ImagesService.upload_base64_data) previously skipped the extension allow-list, so an image/svg+xml mime or an .html filename could be stored under the notes dir and served inline (stored XSS) — the same class fixed for multipart uploads in v0.4.0, now closed for base64 too. Validation runs against the on-disk extension with no bypass; valid AI images are unaffected.

Robustness

  • Atomic note writes (PR #122 by @samirhvbr): Notes are written to a temp file in the destination's own directory and atomically renamed over the target, so an interrupted or failed write (crash, ENOSPC) never truncates the existing note. Integration adds file-mode preservation — the existing note's permission bits are carried across the rename instead of being reset to the umask default.

  • Content search survives invalid-UTF-8 files (PR #123 by @samirhvbr): A single Latin-1/binary .md file no longer aborts the whole search — bad bytes are scrubbed per line, and an unreadable file (permission/TOCTOU) is skipped rather than failing the search.

Features

  • Show where a new note/folder will be created (PR #124 by @samirhvbr): The new-note / new-folder dialog now displays the destination path, so you're not guessing which folder is the target. New strings are translated across all 7 locales. Integration also fixes a pre-existing bug the feature surfaced: a root "New Note" after a cancelled "New Note in Folder" no longer inherits the stale folder.

Chores

  • SimpleCov add_filterskip (silences the deprecation introduced by the simplecov 1.0 bump).

Test Coverage

  • 602 Ruby tests, 1,437 JavaScript tests (2,039 total).

Don't miss a new FrankMD release

NewReleases is sending notifications on new releases.