{"record":{"id":"6ea002da270294c9","repo":"yamadashy/repomix","slug":"refusing-to-access-host-it-is-a-cloud-instance","errorCode":null,"errorMessage":"Refusing to access ${host}: it is a cloud instance metadata endpoint, not a git host.","messagePattern":"Refusing to access (.+?): it is a cloud instance metadata endpoint, not a git host\\.","errorType":"validation","errorClass":"RepomixError","httpStatus":null,"severity":"error","filePath":"src/core/git/gitMetadataEndpoint.ts","lineNumber":124,"sourceCode":"    // git splits host from path at the FIRST colon (so neither user nor host may\n    // contain one), and ssh treats everything before the LAST @ as the user, so\n    // the host is matched after a greedy colon-free user part. It can be a\n    // bracketed IPv6 literal (user@[fd00:ec2::254]:path), so match a bracketed\n    // group before falling back to a plain host.\n    const scpMatch = remoteValue.match(/^[^/:]+@(\\[[^\\]]+\\]|[^/:@]+):/);\n    return scpMatch ? normalizeHost(scpMatch[1]) : null;\n  }\n};\n\nexport const isMetadataEndpoint = (host: string): boolean => BLOCKED_HOSTS.has(host) || LINK_LOCAL_IPV4_RE.test(host);\n\n/**\n * Throws when a remote value points at a cloud metadata endpoint.\n */\nexport const assertNotMetadataEndpoint = (remoteValue: string): void => {\n  const host = extractRemoteHost(remoteValue);\n  if (host !== null && isMetadataEndpoint(host)) {\n    throw new RepomixError(`Refusing to access ${host}: it is a cloud instance metadata endpoint, not a git host.`);\n  }\n};\n","sourceCodeStart":106,"sourceCodeEnd":127,"githubUrl":"https://github.com/yamadashy/repomix/blob/f465ad909315a22120636baf03fa5e28701a50cb/src/core/git/gitMetadataEndpoint.ts#L106-L127","documentation":"Repomix refuses to operate on a git remote whose hostname resolves to a cloud instance metadata endpoint (e.g. 169.254.169.254 on AWS/GCP/Azure). Accessing such endpoints is a well-known SSRF vector, so assertNotMetadataEndpoint throws a RepomixError before any network call is made. It is a deliberate security guard, not a transient failure.","triggerScenarios":"assertNotMetadataEndpoint(remoteValue) is called with a remote URL/string whose extracted host matches a known metadata IP/hostname such as 169.254.169.254 or metadata.google.internal; typically via cloning or fetching a remote value that was passed as --remote or read from a config.","commonSituations":"Malicious or misconfigured repository URLs in CI (SSRF probing); typos or templating bugs where an environment variable like an instance metadata URL is substituted into a git URL; fuzzing/security testing of the remote handling.","solutions":["Replace the remote value with a real git host URL (github.com, gitlab.com, self-hosted instance).","Check where the remote string is generated — fix templating/env substitution that injected the metadata host.","If you control an air-gapped environment and intentionally use such a host, change the hostname mapping; the guard is intentionally not bypassable.","Verify with a guard before calling: extract the host yourself and reject metadata endpoints early."],"exampleFix":"// before\nrepomix --remote http://169.254.169.254/latest/meta-data\n// after\nrepomix --remote https://github.com/user/repo","handlingStrategy":"validation","validationCode":"import { extractRemoteHost } from './src/core/git/gitRemoteUrl.js';\nconst host = extractRemoteHost(remoteValue);\nif (host === null || /(^|\\.)(169\\.254\\.169\\.254|metadata\\.google\\.internal)$/.test(host)) {\n  throw new Error(`Refusing non-git or metadata host: ${host}`);\n}","typeGuard":"const isGitHost = (remoteValue: string): boolean =>\n  /^(https?:\\/\\/|git@)[^\\s/]+\\/[^\\s/]+\\/[^\\s/]+/.test(remoteValue) &&\n  !/169\\.254\\.169\\.254|metadata\\.google\\.internal/.test(remoteValue);","tryCatchPattern":"try {\n  await runRepomix({ remote: remoteValue });\n} catch (e) {\n  if (e instanceof RepomixError && e.message.includes('cloud instance metadata endpoint')) {\n    console.error('Remote URL points at a metadata endpoint; supply a real git host URL.');\n  }\n}","preventionTips":["Never interpolate cloud metadata URLs into git remotes from environment variables.","Whitelist allowed git hosts before invoking repomix --remote.","Lint CI inputs for URL-shaped values pointing at 169.254.169.254."],"tags":["security","ssrf","git","url-validation"],"backgroundTag":"ssrf-metadata-endpoint-blocked","analyzedSha":"f465ad909315a22120636baf03fa5e28701a50cb","analyzedAt":"2026-08-29T01:27:42.024Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}