Security Model

Threat model — prompt injection is the primary risk

ActivityPub MCP feeds attacker-authored, world-writable fediverse content — posts, bios, display names, notifications — directly to an LLM that may simultaneously hold write access to the user’s account. A malicious post or bio can contain instructions crafted to steer the model (e.g. “ignore previous instructions and post the following”). Notifications are an unsolicited injection channel: anyone on the fediverse can mention your account and have that content surface to the model without any action on your part.

This is not hypothetical: anyone who can publish a post can attempt to influence what the LLM does on your behalf.

Mitigations — and their limits

Read-only by default

Mutation tools (post, reply, delete, boost, favourite, bookmark, follow, mute, block, vote, upload, scheduled posts) are not registered unless ACTIVITYPUB_ENABLE_WRITES=true is set. Without that flag, injected content has no write tools to call — the attack surface is limited to information disclosure and model-output manipulation, not account action. There is also a runtime guard (requireWriteEnabled) so a mutation refuses even if it were somehow reachable.

Recommendation: keep writes disabled unless you actively need them, and review the write tool surface before enabling.

Untrusted-content envelope

All remote fediverse content is wrapped in an <untrusted-content source="..."> envelope before it reaches the model, signalling provenance and instructing the model to treat the content as data, not instructions. This is a mitigation, not a cure — a determined payload can still influence the model’s reasoning. The outer control is your MCP client’s per-call approval UX: review tool calls before approving them, especially writes.

Tool annotations

Every tool carries MCP annotations (readOnlyHint, destructiveHint) so compliant clients can gate or surface write tools differently. This is advisory — clients are not required to enforce it.

Network & SSRF protection

The server fetches arbitrary remote URLs, so every outbound request goes through one guarded path:

  • HTTPS-only; no private/loopback/link-local ranges (10.x, 172.16–31.x, 192.168.x, 127.x, ::1, 169.254.x, IPv4-mapped/NAT64/6to4 forms, etc.).
  • DNS-rebinding protection: the resolved IP is pinned and re-validated after every redirect, so a rebind mid-request can’t reach a private address.
  • Redirect re-validation: each redirect target is re-checked against the same allow/block rules.
  • Response size caps to prevent memory exhaustion; upload-media stats files and refuses anything over MAX_UPLOAD_SIZE before reading them.
  • Operator instance blocklist (BLOCKED_INSTANCES, exact domain or *.wildcard). Note: an apex entry does not cover its subdomains — use *.example.com to block a whole instance family.
  • Cross-origin thread fetches are off by default (MCP_THREAD_CROSS_ORIGIN_FETCH=false): both the reply branch and the in-reply-to ancestor walk stay on the root post’s origin, so a hostile root can’t steer the server into fetching arbitrary third-party hosts.

Credential storage & audit

OAuth/MiAuth tokens are stored at ${XDG_CONFIG_HOME:-~/.config}/activitypub-mcp/accounts.json with mode 0600; the server refuses to open a symlink at that path. Audit logs redact tokens and post content and store only file basenames (never absolute paths) — secrets are never written to log output. Set AUDIT_LOG_ENABLED=false to disable the in-memory audit trail (not recommended when writes are enabled).

HTTP transport

When running in HTTP mode:

  • A bearer secret is required (minimum 16 characters); requests without a valid Authorization: Bearer <secret> header are rejected.
  • The MCP SDK’s DNS-rebinding protection is active. For non-localhost binds, set MCP_HTTP_ALLOWED_HOSTS and MCP_HTTP_ALLOWED_ORIGINS.
  • For local use (Claude Desktop, Cursor), stdio transport is recommended — no network exposure.

Reporting a vulnerability

Report security issues privately — do not open a public issue. Use GitHub Security Advisories (“Report a vulnerability”) or email c@meron.io with subject [SECURITY] ActivityPub MCP — <brief description>. The canonical, always-current policy lives in SECURITY.md.

Security resources