MCPEncode stores the facts an organization trusts its agents with, so security reports are taken seriously.
Please do not open a public issue for a security problem.
Report it privately through GitHub: Security → Report a vulnerability on this repository (private vulnerability reporting). Include:
- what an attacker can do, and what they need first (an account, a Reader key, network access);
- steps to reproduce, or a proof of concept;
- the version or commit you tested.
You can expect an acknowledgement within 7 days. This is a spare-time project, so a fix may take longer; you'll be kept informed, and credited in the advisory unless you'd rather not be.
| Version | Supported |
|---|---|
main / latest 0.x release |
Yes |
| Older releases | No |
In scope: the publisher web app, the MCP server, authentication and access control, the publish gate, Reader keys, and anything that lets an agent read unpublished items, write without permission, or reach another library.
Out of scope: running with the example or placeholder secrets, exposing the built-in sign-in to the internet without TLS, and issues in third-party services (Postgres, your MCP client) — report those upstream.
- Run
scripts/init-env.shto generate secrets. The app refuses to start with a placeholderSESSION_SECRET. - The default bind is
127.0.0.1. Put MCPEncode behind a TLS-terminating reverse proxy before exposing it, and setPUBLIC_BASE_URLto thehttps://origin. - Responses carry an enforced Content-Security-Policy with
script-src 'self'(no inline script or handlers, no framing, no third-party loads),nosniff, and HSTS on HTTPS. On an HTTPS address cookies areSecureand__Host-prefixed. Password hashes use scrypt at 64 MiB per hash, at most 2 at once, and older hashes are upgraded at sign-in. - Sign-in misses back off per username and address, per address, and per username across addresses; nothing is hard-locked, so an attacker cannot lock the SA out. Set
TRUST_PROXYbehind a proxy (off by default) and add a per-address limit at the proxy. See docs/deploy.md. - The first account always needs a setup code. Every deploy should set
SETUP_TOKEN(16+ characters) before it is reachable; otherwise a one-time code is printed to the server log at first start. See docs/deploy.md. - MCP clients register their own client id. Only loopback and app-scheme callbacks are accepted by default; add hosted clients' hostnames to
OAUTH_REDIRECT_HOSTS(for exampleclaude.ai); there is no setting that accepts every https host. Every MCP sign-in shows a consent page with the client, callback host and library. - Refresh tokens rotate, are stored hashed, and a reused one revokes its sign-in. Sign-out and a password reset sign the account out everywhere. A sign-in ends 30 days after it started.
- Remote Postgres must use
POSTGRES_SSL=required. - Library MCP routes allow
MCP_RATE_LIMIT_PER_MINUTErequests per client address per minute (default 300,0off) and answer429withRetry-Afterpast that. The address followsTRUST_PROXY. See docs/deploy.md. - Treat each library's Connect link and Reader key as secrets. Rotate them from the publisher UI if they leak. Prefer
X-Library-Tokenfor clients that can set headers, and keep/libraries/*/mcp/*out of proxy logs. - With
AUTH_MODE=oidc, give library MCP its own audience (AUTH_MCP_AUDIENCE) so web sign-in tokens cannot open MCP.