Skip to content

v0.6.2

Choose a tag to compare

@fdemusso fdemusso released this 11 Jul 13:50
· 128 commits to master since this release

BeechCMS v0.6.2

Release Date: July 11, 2026
Pull Request: [#237 — Fix validation issues, enhance API logic, and improve security](#237)


🔒 Security Fixes

  • Public API data masking — Non-string branch values (numbers, booleans, dates, JSON, tags, files) were leaked raw through the public API instead of being nulled out. They are now masked consistently, mirroring apply-policies.ts behaviour. ((#200))
  • Public add endpoint policy enforcement — public-add.ts was writing sanitized data directly to the repository, bypassing applyPrivacy(). Fields with privacy: 'hash' were stored in plaintext and public: false fields could be seeded on create. Privacy policies are now fully enforced on entry creation. ((#201))
  • Filter condition policy enforcement — Public filter conditions were not checked against policies.public / policies.filter, allowing non-public branches (e.g. a field marked public: false) to be used as a data-inference oracle. Filters on hidden branches are now rejected. ((#202))
  • CDN origin spoofing prevention — extractMediaKey used startsWith to match MEDIA_CDN_URL, which could be confused by subdomain or suffix-crafted URLs, allowing unauthorized deletion of unrelated R2 media objects. Now uses exact parsed-origin comparison. ((#222))
  • FTS search index leaking non-public fields — indexableSearchBranches checked policies.search but never policies.public, so full-text search matches on hidden fields (e.g. SSN) could leak content via meta.total. Non-public branches are now excluded from the FTS index. ((#234))

🐛 Bug Fixes

  • Draft _touched_fields race condition — Concurrent saveDraft calls for the same entry could interleave their read-modify-write of _touched_fields, causing a later write to clobber an earlier one. On publish, relation branches missing from _touched_fields would have their junction rows silently deleted without promotion to live. The merge is now handled in a single atomic INSERT ... ON CONFLICT DO UPDATE SQL statement using json_each/json_group_array. ((#210))
  • Hash serialization collision — String(value) coerced JSON, repeater, and richtext branches to the literal "[object Object]" and comma-joined arrays, so every distinct object hashed to the same digest under privacy: 'hash'. All non-string values are now serialized with JSON.stringify before hashing. ((#215))
  • Avatar upload bypassing presigned flow — settingsApi.uploadAvatar posted raw file bytes to a nonexistent /upload route (returning 404), bypassing the required presign → PUT → confirm flow. It now delegates to the existing uploadFile() helper used by RichtextEditor and media.tsx. ((#226))

🛠️ Internal & Maintenance

  • Deduplicated validation cache implementations — A squash-merge of independent fixes (#185 and #190) left stale duplicate implementations of getCachedSchema/setCachedSchema and byteLength in cache.ts and primitives.ts, causing tsc to reject the build. Duplicate implementations have been removed. ((#236))

Upgrading

This release contains critical security fixes for the public API. Upgrading is strongly recommended for all deployments that expose public-facing endpoints. No breaking changes to the existing API contract or schema format are introduced.