{"record":{"id":"b5ecc95324adabd9","repo":"ruvnet/ruflo","slug":"x-ruv-io-response-carries-more-than-one-untrusted-data","errorCode":null,"errorMessage":"x.ruv.io: response carries more than one untrusted-data envelope (tampered response)","messagePattern":"x\\.ruv\\.io: response carries more than one untrusted-data envelope \\(tampered response\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/x-federation-tools.ts","lineNumber":79,"sourceCode":" * errors) parse unchanged.\n */\nconst UNTRUSTED_FENCE =\n  /<<<UNTRUSTED_RELAY_DATA ([0-9a-fA-F-]{36})>>>\\n([\\s\\S]*?)\\n<<<END_UNTRUSTED_RELAY_DATA \\1>>>/;\n\n// Count only NEWLINE-ANCHORED opening markers. A marker inside the body is just\n// characters — the body is one JSON line, so it can never be preceded by a raw\n// newline and can never open a fence. Counting raw occurrences instead would make\n// a publisher able to hard-fail every read simply by typing the marker into a\n// message, which trades a parse bug for a denial of service.\nconst OPEN_MARKER_ANCHORED = /(?:^|\\n)<<<UNTRUSTED_RELAY_DATA /g;\n\nexport function parseGatewayText(text: string): Record<string, unknown> {\n  // One response carries exactly one envelope. More than one means something\n  // upstream spliced an envelope-shaped string into the response, and picking\n  // either is a guess — refuse rather than choose.\n  const opens = (text.match(OPEN_MARKER_ANCHORED) ?? []).length;\n  if (opens > 1) {\n    throw new Error('x.ruv.io: response carries more than one untrusted-data envelope (tampered response)');\n  }\n  const fenced = UNTRUSTED_FENCE.exec(text);\n  if (fenced) return JSON.parse(fenced[2]) as Record<string, unknown>;\n  // An opening marker with no matching close is a truncated or tampered response.\n  // Fail loudly: parsing the remainder would silently drop relay content.\n  if (opens === 1) {\n    throw new Error('x.ruv.io: untrusted-data envelope is unterminated (truncated or tampered response)');\n  }\n  return JSON.parse(text) as Record<string, unknown>;\n}\n\n/**\n * The payload, for consumers INSIDE this package that immediately index the\n * value (`recent.messages`, `Object.keys(roster)`).\n *\n * At the MCP boundary we return the whole envelope so the caller can see whose\n * words these are. Internally that shape is a hazard: reading `.messages` off an\n * envelope yields undefined and `Object.keys()` yields the envelope's own five","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/ruvnet/ruflo/blob/9c61c86f06b439af2a95085ae9bb0ca839662e41/v3/@claude-flow/cli/src/mcp-tools/x-federation-tools.ts#L61-L97","documentation":"parseGatewayText rejects gateway responses from x.ruv.io that contain more than one newline-anchored opening marker `<<<UNTRUSTED_RELAY_DATA <uuid>>>`. A well-formed relay response carries exactly one untrusted-data envelope; seeing two means an upstream hop spliced an envelope-shaped string into the response (a tampered or maliciously crafted payload). Choosing either envelope would be a guess with security implications, so the parser refuses rather than picks one. The count is newline-anchored so a publisher merely typing the marker inside a message body cannot trigger a denial of service.","triggerScenarios":"Thrown at v3/@claude-flow/cli/src/mcp-tools/x-federation-tools.ts:79 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Treat the response as untrustworthy: discard it and do not act on either envelope's contents.","Retry the gateway request once in case the response was corrupted in transit; if it repeats, the tampering is upstream, not transient.","Investigate the relay path (gateway, proxies, MCP transport) for code that concatenates multiple tool/resource responses into one text payload.","If this fires repeatedly for one endpoint, block or flag that gateway URL as compromised and require operator review."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"9c61c86f06b439af2a95085ae9bb0ca839662e41","analyzedAt":"2026-09-22T05:44:27.648Z","contentChangedAt":"2026-09-22T05:44:27.648Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}