abhigyanpatwari/GitNexus · error

Git URLs must not include query strings or fragments

Error message

Git URLs must not include query strings or fragments

What it means

validateGitUrl forbids URLs containing a query string (?...) or fragment (#...). Such components are never meaningful for git remotes and can be used to smuggle parameters past validation, so URLs with parsed.search or parsed.hash are rejected outright.

Source

Thrown at gitnexus/src/core/net/url-guard.ts:29

/**
 * Validate an outbound http(s) URL to prevent SSRF.
 * Only allows https:// and http:// schemes. Blocks private/internal addresses,
 * IPv6 private ranges, cloud metadata hostnames, and numeric IP encodings.
 */
export function validateGitUrl(url: string): void {
  let parsed: URL;
  try {
    parsed = new URL(url);
  } catch {
    throw new Error('Invalid URL');
  }

  if (!['https:', 'http:'].includes(parsed.protocol)) {
    throw new Error('Only https:// and http:// git URLs are allowed');
  }

  if (parsed.search || parsed.hash) {
    throw new Error('Git URLs must not include query strings or fragments');
  }

  const host = parsed.hostname.toLowerCase();

  // Block known dangerous hostnames (cloud metadata services)
  if (BLOCKED_HOSTNAMES.has(host)) {
    throw new Error('Cloning from private/internal addresses is not allowed');
  }

  // Strip IPv6 brackets if present (URL parser behavior varies across Node versions)
  let normalizedHost = host;
  if (host.startsWith('[') && host.endsWith(']')) {
    normalizedHost = host.slice(1, -1);
  }

  // Check if this is an IPv6 address
  // Use manual colon detection as fallback since isIP may return 0 for some
  // normalized IPv6 forms (e.g. ::ffff:7f00:1)

View on GitHub (pinned to 0d1aed942f)

Solutions

  1. Strip the query string and fragment before passing the URL (split at '?' and '#', keep the first part).
  2. Paste the bare clone URL from the repo's 'Clone' button rather than the browser address bar.
  3. Move credentials out of the URL — use an auth header/credential helper instead of ?token=... query params.

Example fix

// before
await cloneOrPull(`https://github.com/acme/api?tab=readme`, dest);

// after
const url = new URL('https://github.com/acme/api?tab=readme');
url.search = '';
url.hash = '';
await cloneOrPull(url.toString(), dest);
Defensive patterns

Strategy: validation

Validate before calling

const cleaned = u.split('#')[0].split('?')[0];
const p = new URL(cleaned);
if (p.search || p.hash) throw new Error('url still has query/fragment');

Type guard

const isBareGitUrl = (u: string): boolean => {
  try { const p = new URL(u); return !p.search && !p.hash; } catch { return false; }
};

Try / catch

try {
  validateGitUrl(url);
} catch (err) {
  if (err instanceof Error && err.message.includes('query strings or fragments')) {
    throw new Error(`strip ?query/#fragment from ${url}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling validateGitUrl (or its callers cloneOrPull / normalizedRegistry / sanitizedHttpUrl) with a URL that includes ?query, #fragment, or tokens pasted from a web UI (e.g. 'https://host/repo?tab=readme' or trailing '#readme').

Common situations: Copy-pasting a repo URL straight from a browser address bar (keeps #anchor or ?params); appending access tokens as query params; template strings accidentally leaving '?ref=...' in the URL.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@0d1aed942f (2026-09-08). Data as JSON: /api/errors/eb0c854cb1f4f137. Report an issue: GitHub.