Skip to content

[Detail Bug] Git SSH URL normalization corrupts IPv6 host when stripping port #309

@detail-app

Description

@detail-app

Detail Bug Report

https://app.detail.dev/org_5f375fe3-a706-4e9a-a6f7-800f2439b3f6/bugs/bug_62520f9a-69a9-4d55-bb09-b99e861d4783

Introduced in #286 by @sachiniyer on May 9, 2026

Summary

  • Context: strip_ssh_port in src/utils/git.rs:35-48 claims to strip ports from SSH URLs.
  • Bug: Produces corrupt output for IPv6 addresses instead of correctly normalized URLs.
  • Actual vs. expected: ssh://git@[::1]:22/owner/repo.gitssh://git@[/owner/repo.git (corrupt) instead of ssh://git@[::1]/owner/repo.git.
  • Impact: Latent bug with no current user impact. Function violates its contract but corruption is masked by prefix matching.

Code with Bug

let (host, _port) = host_port.split_once(':')?; // <-- BUG 🔴 splits at first ':'; breaks IPv6 bracketed hosts

Explanation

IPv6 SSH URLs in URI form use bracketed notation [address]:port (RFC 3986). Using split_once(':') splits on the first colon, which occurs inside the IPv6 literal, producing a malformed host and therefore a corrupt reconstructed URL.

This is currently “invisible” because downstream logic filters by GitHub host prefixes, so the overall parse returns None for non-GitHub hosts—but strip_ssh_port still returns Some(corrupt_url), violating its documented contract (“return the URL with the port stripped” or None).

Failing Test

#[test]
fn strip_ssh_port_handles_ipv6() {
    let result = strip_ssh_port("ssh://git@[::1]:22/owner/repo.git");
    assert_eq!(result, Some("ssh://git@[::1]/owner/repo.git".to_string()));
}

Recommended Fix

Handle bracketed IPv6 hosts by splitting on "]:"; otherwise split on the last ::

let host = if host_port.starts_with('[') {
    host_port.split_once("]:").map(|(h, _)| format!("{h}]"))?
} else {
    host_port.rsplit_once(':').map(|(h, _)| h.to_string())?
};

History

This bug was introduced in commit 88ef9fb. The commit added strip_ssh_port to handle SSH remotes with explicit ports, using split_once(':') which works for IPv4/hostnames but fails for IPv6 [address]:port syntax.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions