CVE-2026-44429
Description
The MCP Registry provides MCP clients with a list of MCP servers, like an app store for MCP servers. Prior to 1.7.7, the public catalogue UI served at GET / (file internal/api/handlers/v0/ui_index.html) is vulnerable to stored cross-site scripting via the server.websiteUrl field of any published server.json. Server-side validation in internal/validators/validators.go (validateWebsiteURL) only checks that the URL parses, is absolute, and uses the https scheme; it does not reject quote characters. Client-side, the value is interpolated into a double-quoted href attribute via innerHTML, using a homegrown escapeHtml helper that performs the standard textContent → innerHTML round-trip. Per the HTML serialisation algorithm, that round-trip encodes only &, <, > and U+00A0 inside text nodes — it does not encode " or '. A literal " in websiteUrl therefore breaks out of the href attribute, allowing arbitrary on* event handlers to be appended to the same <a> element. The Content-Security-Policy on / is script-src 'self' 'unsafe-inline' https://cdn.tailwindcss.com, so the injected event handlers execute. Any user able to obtain a publish token (e.g. via POST /v0/auth/github-at with their own GitHub account, or POST /v0/auth/none on a deployment that has anonymous auth enabled) can plant a poisoned record visible to every visitor of the registry homepage. This vulnerability is fixed in 1.7.7.
Affected products
1- Range: < 1.7.7
Patches
178b7bbde0794fix(validators): reject HTML metacharacters and whitespace in websiteUrl (#1249)
2 files changed · +108 −0
internal/validators/validators.go+14 −0 modified@@ -195,6 +195,20 @@ func validateWebsiteURL(ctx *ValidationContext, websiteURL string) *ValidationRe result.AddIssue(issue) } + // Reject characters that aren't valid in a URI per RFC 3986 and that have + // caused rendering issues when websiteUrl flows into the catalogue UI's + // href attributes. Publishers should percent-encode these in the source URL. + if i := strings.IndexAny(websiteURL, "\"'<> \t\n\r"); i >= 0 { + issue := NewValidationIssue( + ValidationIssueTypeSemantic, + ctx.String(), + fmt.Sprintf("websiteUrl contains an invalid character %q at position %d: %s", websiteURL[i], i, websiteURL), + ValidationIssueSeverityError, + "website-url-invalid-characters", + ) + result.AddIssue(issue) + } + return result }
internal/validators/validators_test.go+94 −0 modified@@ -13,6 +13,8 @@ import ( "github.com/modelcontextprotocol/registry/pkg/model" ) +const websiteURLInvalidCharErrSubstr = "websiteUrl contains an invalid character" + func TestValidate(t *testing.T) { tests := []struct { name string @@ -486,6 +488,98 @@ func TestValidate(t *testing.T) { }, expectedError: "invalid websiteUrl:", }, + { + name: "server with websiteUrl containing double quote", + serverDetail: apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/test-server", + Description: "A test server", + Repository: &model.Repository{ + URL: "https://github.com/owner/repo", + Source: "github", + }, + Version: "1.0.0", + WebsiteURL: `https://example.com/"oops`, + }, + expectedError: websiteURLInvalidCharErrSubstr, + }, + { + name: "server with websiteUrl containing single quote", + serverDetail: apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/test-server", + Description: "A test server", + Repository: &model.Repository{ + URL: "https://github.com/owner/repo", + Source: "github", + }, + Version: "1.0.0", + WebsiteURL: "https://example.com/it's", + }, + expectedError: websiteURLInvalidCharErrSubstr, + }, + { + name: "server with websiteUrl containing angle brackets", + serverDetail: apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/test-server", + Description: "A test server", + Repository: &model.Repository{ + URL: "https://github.com/owner/repo", + Source: "github", + }, + Version: "1.0.0", + WebsiteURL: "https://example.com/<x>", + }, + expectedError: websiteURLInvalidCharErrSubstr, + }, + { + name: "server with websiteUrl containing space", + serverDetail: apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/test-server", + Description: "A test server", + Repository: &model.Repository{ + URL: "https://github.com/owner/repo", + Source: "github", + }, + Version: "1.0.0", + WebsiteURL: "https://example.com/has space", + }, + expectedError: websiteURLInvalidCharErrSubstr, + }, + { + name: "server with websiteUrl containing newline", + serverDetail: apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/test-server", + Description: "A test server", + Repository: &model.Repository{ + URL: "https://github.com/owner/repo", + Source: "github", + }, + Version: "1.0.0", + WebsiteURL: "https://example.com/has\nnewline", + }, + // url.Parse rejects ASCII control chars before our character-set + // check runs; either path produces a validation error. + expectedError: "invalid websiteUrl:", + }, + { + name: "server with websiteUrl with percent-encoded special chars is accepted", + serverDetail: apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/test-server", + Description: "A test server", + Repository: &model.Repository{ + URL: "https://github.com/owner/repo", + Source: "github", + }, + Version: "1.0.0", + WebsiteURL: "https://example.com/path/?q=hello%20world&r=a%22b", + }, + expectedError: "", + }, { name: "server with websiteUrl that matches namespace domain", serverDetail: apiv0.ServerJSON{
Vulnerability mechanics
AI mechanics synthesis has not run for this CVE yet.
References
6- github.com/modelcontextprotocol/registry/security/advisories/GHSA-rqv2-m695-f8j4nvdExploitMitigationVendor Advisory
- github.com/advisories/GHSA-rqv2-m695-f8j4ghsaADVISORY
- github.com/modelcontextprotocol/registry/commit/78b7bbde07948049b916d76b4769faee461ff930ghsa
- github.com/modelcontextprotocol/registry/pull/1249ghsa
- github.com/modelcontextprotocol/registry/releases/tag/v1.7.7ghsa
- nvd.nist.gov/vuln/detail/CVE-2026-44429ghsa
News mentions
0No linked articles in our index yet.