Skip to content

fix(cli): escape registry-supplied text in catalog search and show - #1767

Merged
Dumbris merged 2 commits into
smart-mcp-proxy:mainfrom
rudycelekli:fix/catalog-escape-registry-text-20261023-01
Oct 29, 2026
Merged

Dumbris merged 2 commits into
smart-mcp-proxy:mainfrom
rudycelekli:fix/catalog-escape-registry-text-20261023-01

Conversation

@rudycelekli

Copy link
Copy Markdown
Contributor

Bug

mcpproxy catalog search and mcpproxy catalog show print registry-supplied strings (title, id, publisher, description, install command, required input names) straight to the terminal. The search table only byte-truncates the title, and show prints everything with %s.

These strings come from remote registries (the official registry, Smithery, custom registries entries). An entry whose title or description contains ANSI escapes can clear or rewrite the operator's screen. A newline can forge extra table rows next to a real result, for example a fake ✓ added line.

mcpproxy tools list already escapes upstream-controlled text for this reason, using sanitizeCell/sanitizeDescriptionCell and detect.CapEvidence (GH #938). The catalog commands never got the same treatment.

Trigger

A registry entry with this title:

"\x1b[2J\x1b[1;1HTotally Safe\nofficial  trusted  http  ✓"

Running mcpproxy catalog search <q> or mcpproxy catalog show official/<id> writes the raw ESC sequences to the tty.

Fix

Run the registry-supplied fields through the existing helpers:

  • sanitizeDescriptionCell for prose (the title, which keeps the 40-rune cap, and the description).
  • sanitizeCell for identifiers (id, publisher, transport, install URL and command, input names).

Control and format runes are escaped (made visible), not dropped. JSON/YAML output is unchanged.

Test

TestCatalogOutput_EscapesRegistryControlCharacters renders a poisoned result through printCatalogTable and renderCatalogShow and asserts that neither output contains a raw ESC byte.

Commands run

  • go vet ./cmd/mcpproxy: clean
  • go test -count=1 ./cmd/mcpproxy: ok (cgo build, run locally with SDKROOT set to the macOS 26.5 SDK)
  • With the fix reverted (git stash of catalog_cmd.go), the new test fails with search table wrote a raw ESC to the terminal and show wrote a raw ESC to the terminal.
  • gofmt -l on the edited files: no output

@codecov-commenter

codecov-commenter commented Oct 24, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 96.87500% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cmd/mcpproxy/catalog_cmd.go 96.87% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Review finding (P2): sanitizeCell(s, 0) and sanitizeDescriptionCell(s, 0)
go through detect.CapEvidence, which always caps at 200 runes, so
`catalog search`/`catalog show` cut the catalog ID that `catalog add`
must match exactly and could hide the tail of an install command.
Escape control/format runes with dedicated helpers that do not cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Dumbris

Dumbris commented Oct 26, 2026

Copy link
Copy Markdown
Member

Verified the bug on main and the fix; thank you! The review found one gap, so I pushed a small maintainer commit on top of your branch: sanitizeCell(s, 0) still caps at 200 runes via detect.CapEvidence, so catalog show/search cut the ID (which catalog add must match exactly) and could hide the tail of an install command. The commit escapes control and format runes without truncating (the table title keeps its 40-char cap) and adds TestCatalogOutput_EscapingDoesNotTruncate.

I will merge once CI is green.

@Dumbris Dumbris left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified: the bug reproduces on main and the PR fixes it. The review found one gap, closed by the maintainer commit on top (regression test included). Race tests and CI lint for the touched packages are clean on this branch merged with main, and the result was cross-reviewed clean.

@rudycelekli

Copy link
Copy Markdown
Contributor Author

The remaining binary-build failure on current head dc9eb71fc86bd554269af005654e2f7fa2bdeba2 is in macOS DMG packaging: hdiutil: create failed - Resource busy in create-app-dmg.sh, after the Go core and Swift app bundle were built. The matrix then cancelled the sibling binary jobs.

Failed macOS arm64 job. I attempted to rerun the failed jobs, but GitHub denied the request (Must have admin rights to Repository). A maintainer rerun is needed to determine whether the runner resource error clears; no source change appears justified by this log.

@Dumbris
Dumbris merged commit fb859d4 into smart-mcp-proxy:main Oct 29, 2026
52 of 58 checks passed
@Dumbris

Dumbris commented Oct 29, 2026

Copy link
Copy Markdown
Member

Merged. Thank you, @rudycelekli! catalog search and catalog show now escape registry-supplied text, so a malicious registry entry can no longer inject terminal escape sequences into the CLI output, and IDs stay intact for copy-paste.

Contributions like this are what keep MCPProxy moving, and they matter a lot to the project.

One small ask, only if you feel like it: a short public note about your change (a tweet, a LinkedIn post, a line in a community you are part of) helps more people discover MCPProxy. No pressure at all, and I would be glad to repost it.

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.

3 participants