{"record":{"id":"130ffd79fdff0af0","repo":"ruvnet/ruflo","slug":"peer-url-must-not-embed-credentials","errorCode":null,"errorMessage":"peer url must not embed credentials","messagePattern":"peer url must not embed credentials","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts","lineNumber":256,"sourceCode":"\nfunction writePeers(basePath: string, peers: FederationPeer[]): void {\n  ensureDir(basePath);\n  writeFileSync(peersPath(basePath), JSON.stringify(peers, null, 2) + '\\n');\n}\n\n/**\n * Reject anything that is not a plain http(s) URL to a host.\n *\n * Blocks credentials-in-URL (they would be logged), and non-http schemes such\n * as `file:` which would turn a peer entry into a local file read.\n */\nexport function validatePeerUrl(raw: string): string {\n  let u: URL;\n  try { u = new URL(raw); } catch { throw new Error('peer url is not a valid URL'); }\n  if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n    throw new Error('peer url must be http or https');\n  }\n  if (u.username || u.password) throw new Error('peer url must not embed credentials');\n  return u.origin;\n}\n\nexport function addPeer(\n  basePath: string,\n  input: { nodeId: string; url: string; publicKey: string; label?: string },\n): FederationPeer {\n  if (!NODE_ID_RE.test(input.nodeId ?? '')) throw new Error('nodeId must be 16 lowercase hex chars');\n  if (!HEX64_RE.test(input.publicKey ?? '')) throw new Error('publicKey must be 64 lowercase hex chars');\n  const url = validatePeerUrl(String(input.url));\n\n  const peers = readPeers(basePath);\n  if (peers.length >= MAX_PEERS) throw new Error(`peer registry is full (${MAX_PEERS})`);\n\n  const existing = peers.find(p => p.nodeId === input.nodeId);\n  if (existing) {\n    // Re-pinning a different key for a known nodeId is how a key-substitution\n    // attack would present. Require an explicit remove first.","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/ruvnet/ruflo/blob/2602b642d92234c710ffbe96bfb33007d481ceab/v3/@claude-flow/cli/src/mcp-tools/agentbbs-federation.ts#L238-L274","documentation":"validatePeerUrl rejects URLs containing userinfo (username or password) because peer URLs may end up in logs and registry files, which would leak embedded credentials. Any parseable http/https URL with a non-empty u.username or u.password throws this error.","triggerScenarios":"Calling validatePeerUrl or addPeer with URLs like 'https://user:pass@peer.example.com' or 'http://admin@host/' — any string where the credentials component is present, even empty-password basic auth.","commonSituations":"Copying a URL that included basic-auth credentials from a service dashboard or curl command; shared internal services that embed tokens in the host part; secrets pasted into config files.","solutions":["Remove the credentials from the URL and pass them out-of-band (headers, env vars, a secrets manager)","If the endpoint requires basic auth, configure it at the HTTP client layer rather than in the peer URL","Rotate any credentials that were embedded in a URL — they may already be logged","Re-test with the bare origin, e.g. 'https://peer.example.com'"],"exampleFix":"// before\nvalidatePeerUrl('https://user:secret@peer.example.com');\n// after\nvalidatePeerUrl('https://peer.example.com'); // auth supplied separately via headers/env","handlingStrategy":"validation","validationCode":"const u = new URL(peerUrl);\nif (u.username || u.password) {\n  throw new Error('peer url must not embed credentials; pass them out-of-band');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const origin = validatePeerUrl(rawUrl);\n} catch (e) {\n  if (e.message === 'peer url must not embed credentials') {\n    console.error('Credentials found in peer URL — strip them and supply auth via headers/env; rotate the leaked credential');\n  } else throw e;\n}","preventionTips":["Keep secrets out of URLs; use env vars or a secrets manager","Search configs for '@' in URL hosts before deploying (grep for '://[^/]+@')","If a credential was embedded in a URL, rotate it — it may have been logged","Configure HTTP basic auth at the client layer, not in persisted peer entries"],"tags":["url","security","credentials"],"backgroundTag":"invalid-url","analyzedSha":"2602b642d92234c710ffbe96bfb33007d481ceab","analyzedAt":"2026-09-15T22:58:14.805Z","contentChangedAt":"2026-09-15T22:58:14.805Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}