Security
What this software does with a session, a role and a report — and, in the same breath, what it does not claim. A trust page that only lists the good parts is an advertisement.
How it is built
- A password is a hash and nothing else. PBKDF2-HMAC-SHA256 at 600 000 iterations, a random salt per password, the cost written into the stored value so it can be raised later. Nobody — administrator included — can read one back. A reset is a fifteen-minute single-use link, and setting a new password ends every other session.
- The first run exists only while it is the only way in. On a deployment with no accounts and no identity provider, one surface creates the first administrator; it closes at the first account and refuses afterwards. There are no default credentials anywhere.
- Sessions are opaque and hashed. The browser holds a random token; the database holds a hash of it, the browser it was opened on, and when it was last used. A session lasts twelve hours, or thirty days if the person asked to be remembered at sign-in. Signing out deletes the row; an administrator can end one, or all of somebody's.
- Authority is read on every request. One matrix decides what a role may do, and it is consulted live rather than cached in the session — a demotion takes effect on the next request, not the next sign-in. A group can carry a role for several people at once, and is a way in rather than a decoration.
- A workspace is a scope, not a filter. Every row of work names its workspace, and which workspace a request is about is decided by the session — never by the client. Asking for something in a workspace you are not in answers "there is nothing here", the same as asking for something that does not exist, because naming it would confirm it exists.
- An invitation is a link, not an email row. It works once, for the address it was written for, expires, and can be revoked. A forwarded link needs a sign-in as that person.
- Reports hold no address. The error endpoint stores a message, a stack, the path of the page, the view, the build and the browser. Never a query string, never an IP address — an address is hashed for rate limiting and nothing else.
- No third-party code, anywhere. No analytics, no advertising, no font host, no CDN. The public pages make no request off their own domain, and the application loads nothing it did not ship. There is no cookie banner because there is nothing non-essential to consent to.
- Your work is not training data. Nothing in this product trains a model, and there is no third party in the path to read a board.
- Backups are a copy, and the copy is tested. One SQLite file, copied with
VACUUM INTOwhile the server keeps running, and a restore that checks its own integrity and says what it restored. The drill runs in the test suite on every push.
What is not claimed
These would be the easiest sentences on the page to write and the least true, so they are written as what they are:
- No SOC 2, and none in progress.
- No ISO 27001.
- No penetration-test certificate. When there is one, this line will state who did it and when.
- No uptime target, and no status page. A self-hosted instance is as available as the machine it runs on, and this project does not pretend to watch it.
Accessibility
The target is WCAG 2.2 level AA, which the app's own bar was set to and the public pages share. It is tested rather than asserted: an automated pass runs over the home and product pages on every build, the home page is checked at 320 pixels wide, and the site is checked as a build for structure, headings and landmarks.
Known gaps, stated plainly:
- The board is a dense grid. Dragging a card is the fluent way to move it; the item's own menu is the keyboard way, and both go through the same rule. A screen-reader audit of every screen has not been done.
- Some states are told in colour — a lane at its WIP limit, an item's type — and each has a word beside it, but not always a symbol.
If something stops you, that is a bug worth reporting, not a preference: open an issue.
Report a vulnerability
Open an issue, the same way you would for any other bug. If the detail is the dangerous part, say only that you have a report and we will take the rest somewhere private before you post it.
security.txt is the machine-readable half of this page: the same link, the policy, and an expiry that is checked by the build. SECURITY.md in the repository says the same thing.
The licence
Kanban Toolkit is free software under the GNU Affero General Public License, version 3 or later. Run it, read it, change it, run your changes. The one thing it asks is the point of it: a modified version, run for other people over a network, offers them its source.