Please report vulnerabilities privately via GitHub's security advisories:
Security → Report a vulnerability on this repository (or
https://github.com/lemur47/lemurkit/security/advisories/new).
Do not open a public issue for a security report. You should receive an acknowledgement within a week. Coordinated disclosure is appreciated; you'll be credited in the advisory unless you prefer otherwise.
This project is a self-hosted, single-user MCP connector. Reports of particular interest:
- Auth-gate bypass: any way to reach
/mcptool calls, or obtain a grant, without being the allowlisted GitHub account (OAuth flow, state/CSRF handling, token issuance). - Cross-deployment impact: anything that lets one deployment affect another.
- Secret disclosure: any response path that reflects secret values (the not-configured guard intentionally names missing secret names — that is by design).
- Injection through stored content: object keys/bodies or memory fragments breaking out of their role in tool results.
Out of scope: vulnerabilities requiring the deployer's own Cloudflare or GitHub account to already be compromised; the security of Cloudflare R2/KV/D1/Workers themselves.
- The authorized identity and all OAuth material live in Worker secrets — never commit them.
- The allowlist pins the immutable numeric GitHub id as the primary check; the login is
defence-in-depth. If you rename your GitHub account, update
GITHUB_ALLOWED_USERNAME. - Install-time supply-chain defenses live in
.npmrc(registry pin,ignore-scripts=true, 3-day release cooldown). Keep them when modifying the project. - OAuth
state/carrier tokens are HMAC-signed and expire after 10 minutes (signediat); a captured token stops replaying once stale. Every HTML response (consent, errors, the not-configured checklist) carries a strict CSP, frame denial,nosniff, andno-store. - The Worker ships no application-level rate limiting. The pre-auth endpoints (
/authorize,/register,/token,/callback) are necessarily open — the MCP spec requires dynamic client registration to be unauthenticated — so an unthrottled caller can spam client records into your OAuth KV namespace (storage/cost amplification against your own account). Mitigate at the edge: put the Worker behind a custom domain on a zone you own and add a zone WAF rate-limiting rule (free plan includes one) scoped to those four paths — e.g. 10 requests / 10 s per IP, block. Do not include/mcpin the rule: it's already OAuth-gated and your MCP client calls it on every tool use. A bareworkers.devdeployment has no zone, so it can't use this — Cloudflare's platform DDoS protection still applies, but not per-path throttling.
These are documented trade-offs, not open bugs — reports about them are welcome only if you've found an escalation beyond what's described here.
- Worker observability captures tool traffic.
wrangler.jsoncships withobservability.enabled: true. Tool invocations — including object keys and, on writes, file content passed as arguments — appear in your Cloudflare account's Workers logs and live tail. This is your own account and your own data, but be aware that everything the connector reads and writes is visible there, subject to your account's log retention. Disableobservabilityinwrangler.jsoncif you don't want this. - Semantic prompt injection through stored content. Tool results are JSON-encoded, so stored
content cannot structurally escape its envelope — but file bodies and memory fragments flow to
the model as tool results and can carry instruction-like text. Content you wrote yourself is
as trustworthy as you are; content that arrived out-of-band (dashboard uploads, syncs from
elsewhere) is ingested verbatim by
index_bucketand should be treated as untrusted input to the model. There is no sanitizer that can distinguish "text about instructions" from instructions; the mitigation is what you put in the bucket.
The main branch. There are no maintained release lines; redeploy from current main to pick
up fixes (pushes to your clone's production branch auto-deploy via Workers Builds).