Skip to content

Security: pocketcontext/notifycontext

Security

docs/security.md

Security contract

Ordinary identities are default PocketBase users, verified and enabled. Workspace JIT is validated using server-obtained Google claims; direct signup and ordinary identity management are locked. Account deletion is blocked, and disabled/verification changes rotate tokens. Old disabled tokens cannot access REST, SQL, schema, refresh or record realtime. Authority does not derive from notification content.

All business REST lists/views and record realtime are locked. Custom inbox-change signals are an authenticated, user-specific exception: they carry an empty payload and only prompt a new filtered SQL read. Subscription and delivery checks enforce the matching enabled, verified ordinary account and valid session; operators cannot subscribe on behalf of a user. Signals are emitted only after notification-event or personal-state transactions commit. Recipient actions signal only that recipient and the sender, never fellow recipients. Schema and read-only SQL are the supported application read path. Filtered snapshots expose notification bodies/references only to their sender and recipients. Recipient states/preferences and recipient-action audit events are separately filtered. Senders see recipient responses; one recipient cannot enumerate fellow recipient delivery states or private acknowledgement notes. Shared conversation comments intentionally reveal their author and content to every participant; comment authors are visible through the colleague directory. Public-to-colleagues directory/status are intentionally shared. Auth records, hidden submission payloads, SQL metadata/system tables and extensions are not exported.

Filtered SQL uses the server's synchronous snapshot mode. A requester's private copy is reused only while a dedicated source connection observes an unchanged SQLite data_version; every committed write, including publication, recipient actions, withdrawal, Google claims and account changes, invalidates all retained copies before the next read. Background snapshots and trackChanges are not enabled, so a read after a confirmed write observes it, and stale rows or authorization are never served from the cache. Authentication runs independently on every request before a retained copy is used. At most maxConcurrent (8) copies are retained, in private server temporary files. Per-requester admission (maxConcurrentPerRequester) remains disabled so concurrent tabs of one account are not rejected with 429.

Writes use REST with application-owned transactional validation. Server attribution, timestamps, recipient/reference creation and publication history are not client-controlled. Publication, its recipients, references and initial event commit together. Unique sender/submission key and canonical payload comparison prevent duplicate retries. Recipient updates and personal settings use expected_revision, with idempotent already-satisfied recipient actions. Batch API is disabled; client bulk operations report each separate outcome and are not atomic as a group.

Notification content and references are immutable. Withdrawal retains content/history; archival belongs to each recipient. Acknowledgement is a deliberate action and does not imply work completion. No action follows merely from fetched Markdown, a reference URL or a status message. Summaries and background polling are read-only.

The browser renders sanitized Markdown and does not load remote embedded images. Write / Preview editors use the same sanitizer as saved notification messages, shared comments, private acknowledgement notes and withdrawal reasons. Switching editor tabs performs no API write. External references remain independently authorized by their source applications. Browser bearer tokens persist in the official SDK LocalAuthStore (notifycontext.auth) and remain accessible to same-origin JavaScript; the portable client caches only application tokens in private per-app/server/user files. No bearer tokens or message content enter desktop notification payloads or cross-tab deduplication storage. Desktop notifications require an open authenticated client; they are best-effort attention signals, not evidence of human receipt.

Operators with direct database or backup access are trusted maintenance identities. There is no promise of end-to-end encryption from operators. Backups contain private application data and authentication settings, so the replica must be dedicated and private. Retention is indefinite pending deliberate maintenance erasure; soft withdrawal/archive are not erasure.

Pending email recipients have no account relation and confer no SQL, REST or realtime visibility. Only the sender sees their addresses until claim. Normalization trims and lowercases within the configured Workspace domain without alias or plus-address equivalence. Existing disabled/unverified identities cause publication to fail; a pending address does not bypass account controls.

Pending claims require a server-only marker established after validated Google provider claims. OAuth provisioning and every eligible pending claim share one write transaction; a claim/audit failure prevents token delivery and rolls back all claims and new-account creation. Password login, refresh and operator provisioning cannot claim pending rows. Publication and OAuth run under serialized application transactions to close signup/publication races. All eligible rows are considered; no pagination limit silently leaves a partial claim. A very large pending backlog can lengthen sign-in and is not silently truncated.

The server controls the 30-day pending deadline. Expiry or withdrawal prevents claim without deleting the sender's history. Claimed identity is permanent across email changes. A post-publication operator email change that would collide with an already-linked recipient leaves the pending row unclaimed rather than merging immutable history. No external invitation email is sent.

Shared comments are admitted only for the original sender or a claimed recipient. There is no participant-add API and an unclaimed email grants no access. Claiming an originally addressed email grants access to shared history, with account controls still enforced. Comments, their author, ordering and timestamps are immutable. Author-scoped submission keys reject changed retry payloads; transactions commit comments, per-participant unread updates and audit events together. Personal conversation state is visible and writable only to its owner, including when the notification sender inspects recipient delivery states. Expected revisions protect read/archive actions from consuming later comments. Posting does not mark earlier activity read. Private historical notes are never migrated into shared comments.

There aren't any published security advisories