Skip to content

Release v1.15.2 — abuse query-pattern blocklist + query_log IP/UA attribution#113

Merged
jpr5 merged 1 commit into
mainfrom
feat/v1.15.2-abuse-blocklist
Jun 15, 2026
Merged

Release v1.15.2 — abuse query-pattern blocklist + query_log IP/UA attribution#113
jpr5 merged 1 commit into
mainfrom
feat/v1.15.2-abuse-blocklist

Conversation

@jpr5

@jpr5 jpr5 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Two related changes, shipped together as v1.15.2:

  1. Abuse query-pattern blocklist (src/mcp/abuse-blocklist.ts) — short-circuits searches for off-topic terms identified from production analytics (Toy Story 5 / Disclosure Day / Obsession 2026 / Scary Movie / box-office / SCOTUS Kalshi / CFTC certiorari / sports event contracts). Matched queries return a structured { results: [], blocked: true, domain: ..., hint: ... } response — teaches the calling LLM what's actually in scope. Zero false-positives on legitimate documentation queries (negative tests in src/__tests__/abuse-blocklist.test.ts cover near-miss phrasings like useCopilotAction box for the office layout). Wired into both registerSearchTool and registerKnowledgeTool (search-mode only on knowledge; browse mode has no user query).

  2. query_log attribution columns — added client_ip, user_agent, blocked, block_reason. Per-request IP/UA captured at MCP session init via the same trust-proxy boundary as oauthClientIp, then closed over for the lifetime of the session so every tool call records identical attribution — no more session-id-prefix joins against PostHog for IP attribution. Schema additions are nullable / defaulted (blocked DEFAULT FALSE); backward compatible.

Context

A recent analytics investigation traced a high-volume off-topic empty-query cluster to Anthropic's Claude-User egress pool (160.79.106.32/29) — a shared Anthropic infrastructure pool that ALSO serves legitimate Claude-User fetches to this server (~46k legit sessions/7d). IP-level block would punish ~99.9% legit users. Pattern-based block is the surgical alternative. Long-term defense (scope classifier with adaptive per-session/per-IP reputation) is still on the roadmap.

Observability

A new oauthLog.searchBlocked({ ip, reason, tool }) helper emits [oauth] search_blocked reason=pattern:<name> ip=<ip> tool=<tool> on every block, parallel to the existing [oauth] bearer_failure surface. Greppable for abuse volume independent of the per-row query_log.blocked flag.

Test plan

  • CI green (tsc, prettier, tests, build)
  • Post-merge: smoke-test a known abuse string (e.g. Toy Story 5 box office) on mcp.copilotkit.ai → expect blocked: true response + [oauth] search_blocked log line
  • Smoke-test a legit query (e.g. useCopilotAction onClick handler) → normal results
  • DB inspect: SELECT client_ip, user_agent, blocked, block_reason FROM query_log ORDER BY created_at DESC LIMIT 10; — confirm new columns populated

@jpr5 jpr5 merged commit 5ee4168 into main Jun 15, 2026
8 checks passed
@jpr5 jpr5 deleted the feat/v1.15.2-abuse-blocklist branch June 15, 2026 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant