docs(specs): spec 100 — per-prompt rug-pull baseline (Spec 032 parity) - #1009
Merged
Conversation
… for prompts) The deferred "big one" from the PR #973 review (finding F2, rug-pull half). Aggregated upstream prompts have scope, sanitisation, TPA description scanning, logging, caps, naming hardening, and reactive refresh — but no CHANGE detection. A trusted server can pass admission with a benign prompt and later mutate its metadata with no review and no record. This specs the tool-quarantine (Spec 032) analogue for prompts. Key design decisions captured: - Baselines advertised LIST metadata only (name+description+args); get-time message content is inherently not cheaply baselineable — stated loudly as the headline Non-Goal so it is never mistaken for content protection. - Enforcement is by WITHHOLDING (not registering a changed prompt = list-hide + native get-fail), so there is NO runtime get-time gate to build — the biggest simplification over tools. - Parallel PromptApprovalRecord/bucket (not a ToolApprovalRecord overload). - Reuses the quarantine_security approve path; a ~300-400 LOC MVP delivers the whole security guarantee, with REST/Vue/scan-mode explicitly deferred. Spec-only; no code. Implementation (MVP first) is a follow-up task under this spec. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H7J8Yv5zr4tMQZaY3ot3Za
Deploying mcpproxy-docs with
|
| Latest commit: |
4f29752
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://84d873c8.mcpproxy-docs.pages.dev |
| Branch Preview URL: | https://100-prompt-rugpull-baseline.mcpproxy-docs.pages.dev |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
📦 Build ArtifactsWorkflow Run: View Run Available Artifacts
How to DownloadOption 1: GitHub Web UI (easiest)
Option 2: GitHub CLI gh run download 32253908107 --repo smart-mcp-proxy/mcpproxy-go
|
Dumbris
added a commit
that referenced
this pull request
Aug 19, 2026
Implements the core of spec 100 (merged in #1009): the tool-quarantine (Spec 032) analogue for aggregated upstream prompts. A trusted server that passes admission with a benign prompt and later mutates its advertised metadata is now caught and the changed prompt is WITHHELD from prompts/list until approved — closing the last F2 gap from the PR #973 review. Scope (metadata only): the baseline hashes advertised LIST metadata (name + description + arguments); get-time prompts/get message content is inherently not baselineable here (spec Non-Goals) and stays defended by the existing F2 sanitisation + F12 caps. - storage: parallel PromptApprovalRecord + prompt_approvals bucket + CRUD (+ Manager wrappers), mirroring the tool ops 1:1 — NOT a ToolApprovalRecord overload (the server:tool / server:prompt key spaces would collide). - engine (internal/server/prompt_quarantine.go): calculatePromptApprovalHash (sha256(name|desc|normalizeJSON(args)), excludes Meta/Title), checkPromptApprovals with the pending/changed/approved state machine + baseline-pass + QuarantineEnabled kill-switch + TrustMode/AutoApproveToolChanges reuse, a fail-closed enforcePromptInvariant transition spine, filterBlockedPrompts, and the ApprovePrompt/ApproveAllPrompts mutators (which re-baseline + RefreshPrompts()). - hook: checkPromptApprovals + filterBlockedPrompts run in RefreshPrompts after the TPA scan-and-drop, before registration. Withholding IS the block — a prompt never passed to SetPrompts is absent from prompts/list and fails prompts/get natively, so there is no runtime get-time gate. Tests: hash stability/change, fail-closed invariant, first-seen→pending, approve→registered, rug-pull change→withheld→revert→re-approved, trust=auto auto-approve, ApproveAllPrompts, and a full-RefreshPrompts withholding integration test. Existing aggregation tests set quarantine off (they verify aggregation, not the baseline). Deferred to a follow-up: the quarantine_security MCP ops (inspect_prompts/approve_prompt/approve_all_prompts), REST twins, and the Vue review banner — the approve API (ApprovePrompt/ApproveAllPrompts) is ready to wire. Adding the MCP tool-schema op requires regenerating the 3 frozen tool-surface goldens, done deliberately in that PR. Claude-Session: https://claude.ai/code/session_01H7J8Yv5zr4tMQZaY3ot3Za Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The last deferred item from the PR #973 multi-model review — finding F2's rug-pull half. Aggregated upstream prompts now have scope enforcement, content sanitisation, TPA description scanning, activity logging, size caps, name hardening, and reactive refresh (#973/#1005/#1006/#1007) — but no change detection. Tools carry a per-item approval hash (Spec 032) so a trusted server can't silently swap an approved tool's contract; prompts have no equivalent, so a server can pass admission with a benign prompt and later mutate it with no review and no record.
This is spec-only — no code. The design workflow's honest verdict was that the full parity feature is ~1600–2000 LOC across ~12 files (storage record + bucket, a hash/state-machine engine with the fail-closed
enforceInvariantspine, the RefreshPrompts hook, MCP/REST/Vue review surfaces), which is spec-worthy by this repo's conventions rather than a drive-by PR. So this PR is the decision point.Key design decisions captured
prompts/getmessage content has no list-time artifact to hash against and is inherently not cheaply baselineable — stated loudly as the headline Non-Goal so it's never mistaken for content protection (that path stays defended by F2 redaction + F12 caps).PromptApprovalRecord/bucket, not aToolApprovalRecordoverload (theserver:toolvsserver:promptkey spaces collide).quarantine_securityapprove path; a ~300–400 LOC MVP delivers the whole security guarantee, with REST twins, the Vue banner,trust_mode: scan, and a dedicated config dial explicitly deferred.The
enforceInvariantport is security-critical (the fail-closed guarantee), which is itself the argument for a spec + review rather than a quiet PR.Next
If the shape looks right:
speckit.plan→speckit.tasks, then implement the MVP as the first task. Happy to proceed on your go-ahead.🤖 Generated with Claude Code