diff --git a/lib/realtime.js b/lib/realtime.js
index 35b86266..3903eb6f 100644
--- a/lib/realtime.js
+++ b/lib/realtime.js
@@ -29,6 +29,8 @@ const realtime = {
maintenance: true
}
+const allowedPermissionValues = ['freely', 'editable', 'limited', 'locked', 'protected', 'private']
+
function onAuthorizeSuccess (data, accept) {
accept()
}
@@ -363,13 +365,25 @@ function connectNextSocket () {
}
function checkViewPermission (req, note) {
- if (note.permission === 'private') {
- if (req.user && req.user.logged_in && req.user.id === note.owner) { return true } else { return false }
- } else if (note.permission === 'limited' || note.permission === 'protected') {
- if (req.user && req.user.logged_in) { return true } else { return false }
- } else {
+ const permission = note.permission
+
+ // Private notes should only be readable to their owner
+ if (permission === 'private') {
+ return req.user && req.user.logged_in && req.user.id === note.owner
+ }
+
+ // Limited and protected notes should be readable by all logged-in users
+ if (permission === 'limited' || permission === 'protected') {
+ return req.user && req.user.logged_in
+ }
+
+ // Freely, Editable and Locked notes should be readable by everyone
+ if (permission === 'freely' || permission === 'editable' || permission === 'locked') {
return true
}
+
+ // Invalid permission
+ return false
}
let isConnectionBusy = false
@@ -636,6 +650,10 @@ function ifMayEdit (socket, callback) {
// only owner can change
if (!note.owner || note.owner !== socket.request.user.id) { mayEdit = false }
break
+ default:
+ // invalid permission
+ mayEdit = false
+ break
}
// if user may edit and this is a text operation
if (socket.origin === 'operation' && mayEdit) {
@@ -778,7 +796,14 @@ function connection (socket) {
const note = notes[noteId]
// Only owner can change permission
if (note.owner && note.owner === socket.request.user.id) {
- if (permission === 'freely' && !config.allowAnonymous && !config.allowAnonymousEdits) return
+ // If config disallows freely permission, do not set it
+ if (permission === 'freely' && !config.allowAnonymous && !config.allowAnonymousEdits) {
+ return
+ }
+ // Ignore invalid permission values
+ if (!allowedPermissionValues.includes(permission)) {
+ return
+ }
note.permission = permission
models.Note.update({
permission
diff --git a/public/docs/release-notes.md b/public/docs/release-notes.md
index a06bc417..5679c7f5 100644
--- a/public/docs/release-notes.md
+++ b/public/docs/release-notes.md
@@ -2,6 +2,10 @@
## 1.11.1 2026-07-24
+### Security fixes
+
+- [GHSA-93w7-49m2-cqwg](https://github.com/hedgedoc/hedgedoc/security/advisories/GHSA-93w7-49m2-cqwg) reports possible corruption of permission values due to missing validation. This should not impact permission checks, except when the note owner intentionally set their note permission to something invalid.
+
### Enhancements
- Added external link warning setting (`externalLinkWarning` in config.json or `CMD_EXTERNAL_LINK_WARNING`) to disable the external link warning page entirely