N Noer

Inkstone Security and Recovery Review: A Threat Register for Self-Hosted Notes

A practical security and recovery review for Inkstone self-hosting: Cloudflare control planes, owner recovery, backups, shares, MCP/API keys, updates, restore evidence, and operator duties.

Inkstone is best reviewed as self-hosted knowledge infrastructure, not as another hosted notes account. The application gives the owner a Markdown-first notebook on Cloudflare Workers with D1 for notes and account data, R2 or KV for attachments, optional Workers AI for semantic search, public note sharing, private remote MCP access, offline editing, exports, and manual or scheduled WebDAV or S3-compatible backups. That is a strong operating model for people who want control, but it also moves several security and recovery responsibilities from a vendor operations team to the deployer.

This review does not assert a vulnerability in Inkstone. The useful question is narrower and more operational: if a personal or small-team notebook becomes important, what can fail, what does Inkstone appear to control, what must the operator control, and what evidence should exist before trusting the deployment with long-lived notes?

Security boundary

The official project describes Inkstone as self-hosted software rather than a hosted service. That boundary matters. Inkstone can provide application-level features such as authentication, version history, exports, share controls, OAuth-based MCP access, revocable API keys, bounded reads, revision-safe writes, separate trash permission, grant management, backup flows, and automatic database migrations. It cannot protect a Cloudflare account that has weak identity controls, a custom domain delegated to the wrong place, a backup bucket controlled by another party, or an owner password that nobody can recover.

The product and the operator therefore have different jobs. Product controls reduce application risk once the instance is running correctly. Operator controls protect the cloud account, domain, secrets, update process, backup destinations, and restore procedure around the application. A serious review should keep those two categories separate so that product features are not mistaken for an operations program.

Threat and operations register

1. Cloudflare account compromise

The highest-impact failure is compromise of the Cloudflare account that owns the Worker, D1 database, R2 bucket or KV namespace, custom domain, environment bindings, and deployment pipeline. If that account is taken over, the attacker may be able to change code, read or delete stored data, alter DNS, rotate bindings, disable the Worker, or point the domain at a different service. Inkstone's in-app access controls cannot fully defend against an attacker who controls the hosting account.

Product controls: Inkstone runs inside the owner's Cloudflare environment and keeps note data in owner-managed storage rather than in a third-party notes service. That improves control when the account is well protected.

Operator responsibilities: require strong multi-factor authentication on Cloudflare and GitHub, remove unused account members, use least-privilege deployment access, monitor account audit events where available, protect recovery email accounts, and keep an inventory of the Worker, D1 database, R2 or KV storage, Durable Objects, AI binding, and custom domain used by the instance.

2. Custom domain and access policy drift

A self-hosted notebook often starts on a generated Workers URL and later moves behind a custom domain. That domain becomes part of the trust boundary. DNS mistakes, stale routes, permissive access policies, or forgotten preview deployments can expose an instance in ways the owner no longer remembers.

Product controls: Inkstone has its own sign-in boundary and supports owner-managed deployment. Public sharing is a separate feature rather than the default state of the whole notebook.

Operator responsibilities: document every hostname that reaches the Worker, decide whether Cloudflare Access or another outer access layer is required, remove obsolete preview URLs from routine use, verify TLS and routing after changes, and test access from a clean browser session rather than assuming that an authenticated admin session represents the public view.

3. Owner password loss

Inkstone's security policy states that it does not provide a password-reset bypass. Losing the owner password means recovery depends on a trusted backup or reinitializing the instance. This is a deliberate boundary, not a defect: a reset bypass that works without the owner's credentials would itself become a sensitive recovery channel.

Product controls: the absence of an easy bypass protects against casual account takeover through a weak reset flow.

Operator responsibilities: store the owner credentials in a password manager, protect the password manager's recovery path, keep at least one tested backup that can rebuild the notebook, and write down who is allowed to perform an emergency reinitialization if the instance is used by more than one person.

4. Backup destination credentials

Inkstone supports exports and off-site backups to WebDAV or S3-compatible storage. The README says remote backups use a verified Markdown snapshot format and can include readable notes, archived and trashed notes, attachments, and a completion marker. It also states that login passwords, active sessions, share passwords, and backup-service credentials are not included in exports. Backup destinations are still sensitive because a complete note snapshot may contain private writing, operational notes, credentials pasted into notes, or attachment data.

Product controls: Inkstone supports manual and scheduled backups, multiple targets, export formats, attachment export, duplicate attachment handling inside snapshots, and a CredentialVault Durable Object for the key used to encrypt backup credentials.

Operator responsibilities: choose a backup destination with its own strong authentication, restrict credentials to the minimum required bucket or path, rotate destination credentials when people or devices change, avoid storing unrelated data in the same bucket, and treat backup snapshots as sensitive plaintext unless the destination adds encryption and access logging that the operator has verified.

5. Public share exposure

Public note links are useful for publishing a single note or temporarily sharing knowledge. They are also a common source of accidental disclosure because the note may later be edited to include information that was not intended for the original audience.

Product controls: Inkstone supports public note links with optional access passwords and expiration dates. Release notes for v0.8.0 also mention attachment references in Markdown examples being included in authorization, sharing, backups, and reference cleanup, which is relevant to share completeness and attachment handling.

Operator responsibilities: use expirations for temporary links, use passwords when the audience is not fully public, review active shares on a schedule, avoid sharing notes that are also used as private working documents, and retest shared pages in a logged-out browser after editing notes with attachments or embedded content.

6. Remote MCP and API key scope

Inkstone's private remote MCP support is powerful because it allows authorized AI tools to search, fetch, and write notes. That expands the security boundary beyond the browser UI into agent clients, API keys, OAuth grants, and the devices where those clients run. The risk is not that MCP is inherently unsafe; the risk is treating an automation credential like a harmless convenience token.

Product controls: the official README describes OAuth 2.1 with PKCE, revocable ink_... API keys, standard search and fetch operations, bounded reads, revision-safe writes, separate trash permission, and per-account grant management.

Operator responsibilities: issue separate keys for separate tools, revoke unused grants, avoid placing long-lived keys in shared shell history or project repositories, keep AI clients on trusted devices, limit write access when read-only retrieval is enough, and review whether any external tool connected through MCP stores prompts, retrieved notes, or logs outside the Inkstone instance.

7. Dependency and update drift

Self-hosting creates an update obligation. Inkstone v0.8.0 includes automatic, idempotent D1 migrations and states that existing notes, folders, tags, attachments, shares, backups, sessions, offline edits, and account settings remain compatible for that release. It also recommends keeping a current backup before updating. That is the right posture: migrations reduce manual database work, but they do not remove the need for a rollback and restore plan.

Product controls: versioned migrations, owner-only update notifications, documented verification commands, and compatibility notes in releases help the operator update safely.

Operator responsibilities: track the deployed version, read release notes before updating, keep a backup made immediately before a production update, test the update path on a non-critical copy when practical, and record which Git revision or release tag is deployed. Do not let a fork drift indefinitely without reviewing security fixes from the latest release and default branch.

8. Restore evidence

A backup that has never been restored is only a hope. Inkstone's export and backup design is promising because Markdown snapshots are directly readable and large backups can be restored by selecting the backup folder rather than loading one complete archive into memory. The operational control is still the same: prove that a real restore works before the first emergency.

Product controls: readable Markdown exports, JSON and ZIP exports, attachment export, completion markers, manual backups, scheduled backups, and large-backup restore behavior provide the building blocks for recovery.

Operator responsibilities: keep restore evidence. At minimum, record the date of the last restore test, the backup target used, whether notes, archived notes, trashed notes, attachments, and settings were checked, and what was intentionally not expected to restore, such as active sessions, passwords, share passwords, or backup-service credentials.

Practical mitigation checklist

  • Identity: protect Cloudflare, GitHub, email, and backup-provider accounts with strong MFA and password-manager-stored credentials.
  • Inventory: record the Worker name, D1 database, R2 bucket or KV namespace, Durable Objects, custom domains, backup destinations, and deployed release tag.
  • Access: review Cloudflare account members, GitHub repository access, MCP grants, API keys, and public shares on a recurring schedule.
  • Backups: configure at least one off-site destination, run a manual backup before updates, and keep destination credentials scoped to the Inkstone backup path.
  • Recovery: perform a restore test and save evidence, including the backup date, restore date, sample notes checked, attachment checks, and known non-restored secrets.
  • Updates: follow stable releases, read migration notes, update from a known Git tag, and avoid making untracked production changes that cannot be reproduced.
  • Sharing: prefer expiring links, password-protect non-public shares, and review shared notes after edits that add attachments, embeds, or operational details.
  • Automation: treat remote MCP and ink_... keys as production credentials. Separate tools by key, revoke stale grants, and keep keys out of repositories and logs.

Adoption judgment

Inkstone is a good fit for an owner who wants Markdown portability, Cloudflare-based self-hosting, browser and mobile access, optional AI search, public sharing, and off-site backup control, and who is willing to operate the surrounding account and recovery model. It is a weaker fit for someone who wants a hosted-service recovery desk, vendor-operated account recovery, or a system where forgotten passwords and lost cloud accounts can be solved without prior backup discipline.

The differentiated point is not that Inkstone is risky because it is self-hosted. The point is that its security posture is inseparable from the operator's Cloudflare, domain, backup, and credential posture. Treat it like a small personal knowledge system with real control-plane dependencies. If Cloudflare identity is hardened, shares and MCP keys are reviewed, backups are scoped and tested, and update drift is managed, the architecture gives the owner meaningful control. If those duties are ignored, self-hosting becomes only a different place to lose data.