docpack Docs
Ctrl K
UP TO DATE Reviewed 3 days ago · next review Apr 25, 2027 Edit this page

Security and data handling

reference · last reconciled 2026-10-29 by claude · docs/security.md

Contents 13 sections · ~2,413 tokens whole page · every section is individually addressable
  1. 1 What the GitHub App can access ~1,056
  2. 1.1 What it reads ~333
  3. 1.2 What it writes, and how ~461
  4. 2 Transport ~85
  5. 3 Storage and encryption ~110
  6. 4 Keys and tokens ~185
  7. 5 Sessions ~115
  8. 6 Who can read a private space ~149
  9. 7 Agent access (MCP) ~134
  10. 8 Webhooks ~82
  11. 9 What the operator can and cannot see ~208
  12. 10 Where your data is processed ~56
  13. 11 Reporting a vulnerability ~63

Token figures are estimates — chars/4 (estimate — docpack has no tokenizer). Section run receipts are not shown: docpack’s runs: ledger records a run against a PAGE, never a section, so a per-section outcome would be invented.

The docpack GitHub App reads the repositories you choose and builds your docs from them. It writes back in two ways: edits and the starter pack arrive as pull requests, and run receipts from keys with "Record runs" ticked are committed directly to your default branch. It never pushes anything else to your default branch. Your docs are stored with Google Cloud in the United States. API keys are stored only as hashes. The operator can technically read the built copy of a private space; the controls below limit who else can. For how personal data is handled, see Privacy.

Report a vulnerability to max.lisaius@gmail.com.

1What the GitHub App can access

You pick the repositories when you install the app. It can only reach those. You can change the list on GitHub at any time, and uninstalling removes all access.

Permission Level Why we need it
Contents Read and write To download a repository so we can build your docs, and to commit the changes described below
Pull requests Read and write To open pull requests for edits and for the starter pack, and to find the pull request we already opened
Metadata Read GitHub requires it for every app; it lists repositories and their default branch

The app also receives push events and installation events from GitHub, so it can rebuild when you push.

The permission set is configured in the GitHub web console, not in our code, so it is not recorded with the source. Check the live list on the app's page on GitHub before you install.

For sign-in, GitHub also asks you to share your email addresses (read only). We use that to find your one verified primary address.

1.1What it reads

  • The repository list for your installation.
  • Each repository's default branch and latest commit.
  • A download of a whole repository at one commit. We need the whole repository to find your docs folder and to work out which docs are out of date against the code they describe. Files outside your docs folder are held in temporary storage during the build and then deleted. They are not rendered, and their contents are not kept. The build does keep the names of directories outside your docs folder, in a coverage snapshot stored with the built site.
  • Individual files, commit history, and comparisons between commits, for freshness checks.
  • Repository Markdown files that a page includes. A page can take its text from a Markdown file elsewhere in the same repository (its source:). The path must be relative, clean, forward-slashed, end in .md and contain no .., and it is read through a handle rooted at the repository, so a symlink or junction cannot lead outside it. The extraction of the downloaded repository skips symlinks and marks its top directory as the repository root, so a hostile source: cannot reach files beside or above the tree. A source that fails any of this is refused with a build error, and nothing outside the repository is read or copied into the built site or the agent bundle.

1.2What it writes, and how

  • Edits from the hosted editor, and edits suggested by agents. These always go to a branch named docpack/edit- followed by the space and page, and we open a pull request into your default branch. Nothing changes on your default branch until someone on your team merges. A save that leaves the page byte-for-byte unchanged writes nothing and opens no pull request. The editor's email address (or, for an agent's key, the key's label) appears in the commit message and, for editor saves, the pull request text.
  • Image uploads from the editor. Same branch, same pull request.
  • Starter docpack. If a repository has no docpack, an admin can ask for a starter pack. It arrives as a pull request from the branch docpack/starter-pack.
  • Included pages. The hosted editor refuses to save a page that takes its text from another file, so it never writes to the source. A run receipt on one is still added to the stub page only, and the app fetches the source file from the same repository, and the same validated path, to fingerprint it.
  • Run receipts. A key with "Record runs" ticked can log that a documented process was run. We add one entry to that doc's run history and commit it directly to the branch the space is built from (your default branch when the space was connected), with no pull request. The commit message names the key's label or the admin's email address. Keys do not have this permission unless you tick it. If your default branch is protected against direct pushes, these commits will fail.

The app never deletes branches or files, and never force-pushes. It does not touch any repository you did not select.

The app's access token is not narrowed to one repository per request. Each token carries the full installation grant for one hour and is kept only in server memory.

2Transport

Traffic to docpack.dev uses HTTPS, ended at Google Cloud Run. Session cookies are marked Secure and HttpOnly. Files are served with a header that stops browsers from guessing file types, and private pages are marked not cacheable by shared caches. We do not currently set HSTS, Content-Security-Policy or X-Frame-Options headers.

3Storage and encryption

Settings and records are in Google Firestore. Built sites and the source copy are in a Google Cloud Storage bucket that cannot be made public. Both are encrypted at rest by Google using Google-managed keys. We add no extra layer of our own encryption, and we do not offer customer-managed keys.

Everything is in the United States. The service and files are in Iowa. The database is in a United States multi-region.

4Keys and tokens

  • A key is 32 random bytes. We store a SHA-256 hash and never the key itself. The full key is shown once, when you create it.
  • Keys do not expire. They stay valid until you revoke them or you uninstall the app.
  • Every key has permissions you choose: read, suggest edits, record runs, publish, or limited admin. A key can be limited to chosen spaces. A key from one organization cannot read another organization.
  • A limited admin key can make a space more private, create a private space, and delete spaces it can reach. It cannot make anything public, add readers or editors, create keys, add admins, or reach billing.
  • Revoke a key on the dashboard. It stops working within about 30 seconds on every server instance.

5Sessions

Sign-in uses GitHub or Google. We keep only a signed cookie for 12 hours. The signature stops forgery; it does not hide your email address from someone who has your browser. Signing out removes the cookie from your browser but does not cancel a copy someone already took. The sign-in step is protected against cross-site forgery and open redirects.

Dashboard changes are protected by the SameSite=Lax cookie setting and not by separate form tokens.

6Who can read a private space

A private space is readable by people whose verified email is on its reader or editor list, by admins of the organization, and by keys of that organization that reach the space. Anyone else, signed in or not, gets the same answer as for a space that does not exist. A domain entry matches the domain of the verified email only.

Choosing "public" for a space publishes every page unless you also tick "Only pages marked public". With that box ticked, only pages marked public are built into the public copy, and notes and covered source paths are removed from them.

7Agent access (MCP)

Agents connect to a space over HTTPS with a key, or with no key for a public space. Writes are checked separately: logging a run (with either the log or the record-change tool) needs "Record runs", and suggesting an edit needs the edit permission. Anonymous calls to public spaces are limited to 120 tool calls a minute per IP address, per server instance. Calls with a key count against your plan's monthly allowance. Requests are capped at 16 MB. We do not log tool arguments, so search queries are not recorded.

8Webhooks

GitHub and Stripe events are accepted only if their signature checks out against a shared secret, and nothing in a request is acted on until its signature checks out. A bad signature gets a 401. If a secret is not configured, the endpoint is not served at all. Stripe signatures older than five minutes are rejected.

9What the operator can and cannot see

The operator can read:

  • Settings, reader and editor lists, and admin lists, in the database.
  • The built copy and the Markdown source copy of every space, including private ones, in storage.

There is no technical control that stops a person with operator access from reading them. It is an access-control and trust commitment, not something the software enforces. Our own log lines hold ids, repository names, GitHub logins, commit ids and error text, and do not hold document text, search queries, email addresses, keys or tokens. Google Cloud's platform also records standard request details.

The operator cannot see your payment details; Stripe holds them. The operator cannot read your repositories beyond what the app's permissions allow, and only for the repositories you selected.

10Where your data is processed

Google Cloud (hosting, database, storage, logs), GitHub (the app and sign-in), Google (sign-in), Stripe (billing) and Cloudflare (DNS only). The full list is on the Privacy page.

11Reporting a vulnerability

Email max.lisaius@gmail.com with what you found and how to reproduce it. Please do not test against other customers' data, and give us reasonable time to fix a problem before you publish it. We will acknowledge your report.

Run history
● 2026-10-29 · reconciled · claude
● 2026-10-29 · corrected · “(note withheld from the public build)”
● 2026-10-29 · reconciled
● 2026-10-28 · corrected · claude · “(note withheld from the public build)”
● 2026-10-27 · reconciled · claude
show all 6 runs
● 2026-10-27 · corrected · claude · “(note withheld from the public build)”