Git development
 help / color / mirror / Atom feed
* [BUG] http: push with token-only URL userinfo fails after libcurl strips creds from CURLINFO_EFFECTIVE_URL
@ 2026-10-16 22:36 Dan
  2026-10-21 11:23 ` Tuomas Ahola
  0 siblings, 1 reply; 2+ messages in thread
From: Dan @ 2026-10-16 22:36 UTC (permalink / raw)
  To: git

Hi,

(Please note this was done with the assistance of Claude, I apologize
if there are inaccuracies here, Ive tried to go over this and verify
as much of it as I am capable of. I tried looking at the mailing list
archives to see if this has already been reported and I didnt see
anything that looked like it had yet. I can verify that the new
libcurl behavior absolutely seems to be causing issues from at least
my own limited vantage point. -Dan)

Since libcurl stopped returning credentials in CURLINFO_EFFECTIVE_URL
(curl 8.23.0, commit 7a6bd027d0de "getinfo: make sure
CURLINFO_EFFECTIVE_URL does not contain creds", CVE-2026-94266; also
backported to Ubuntu 24.04 as curl 8.5.0-2ubuntu10.16, USN-8932-1),
pushing over smart HTTP fails when the remote URL carries a username
but no password, e.g.

    https://<token>@forge.example/owner/repo.git

which is a common way for CI tools to pass an access token (Renovate
does this for Gitea/Forgejo). Fetch/clone keep working; push does not.

Versions
--------
  git 2.55.0 (1:2.55.0-0ppa1~ubuntu24.04.2)
  libcurl3t64-gnutls 8.5.0-2ubuntu10.16    -> fails
  libcurl3t64-gnutls 8.5.0-2ubuntu10.15    -> works (same git build)
  Server: Forgejo 16.0.6 (answers the first unauthenticated request
          with 401 + "WWW-Authenticate: Basic realm=...")

Reproduce
---------
  git clone https://<token>@forge.example/owner/repo.git && cd repo
  git commit --allow-empty -m test
  GIT_TERMINAL_PROMPT=0 git push origin HEAD:refs/heads/test

Expected: push succeeds (it did with the previous libcurl).
Actual:

  Pushing to https://forge.example/owner/repo.git
  warning: redirecting to https://forge.example/owner/repo.git/
  POST git-receive-pack (815 bytes)
  fatal: could not read Username for 'https://forge.example': No such
device or address
  send-pack: unexpected disconnect while reading sideband packet
  fatal: the remote end hung up unexpectedly

No redirect happens on the server side; the server log shows
GET info/refs 401 -> GET info/refs 200 -> POST git-receive-pack 401.

GIT_TRACE_CURL (abridged, credentials redacted):

  => Send header: GET /owner/repo.git/info/refs?service=git-receive-pack HTTP/2
  <= Recv header: HTTP/2 401
  <= Recv header: www-authenticate: Basic realm="Gitea"
  == Info: Issue another request to this URL:
'https://<cred>@forge.example/owner/repo.git/info/refs?service=git-receive-pack'
  == Info: Server auth using Basic with user '<redacted>'
  => Send header: GET /owner/repo.git/info/refs?service=git-receive-pack HTTP/2
  => Send header: Authorization: <redacted>
  <= Recv header: HTTP/2 200
  warning: redirecting to https://forge.example/owner/repo.git/
  == Info: [HTTP/2] [5] OPENED stream for
https://forge.example/owner/repo.git/git-receive-pack
  => Send header: POST /owner/repo.git/git-receive-pack HTTP/2
     (no Authorization header)
  <= Recv header: HTTP/2 401

Analysis
--------
In http.c, http_request_reauth() calls update_url_from_redirect() with
the URL git asked for and CURLINFO_EFFECTIVE_URL. The asked-for URL
still contains "<token>@", but libcurl now returns the effective URL
without userinfo, so the strcmp() differs and git treats an ordinary
200 as a redirect: it prints "redirecting to ...", rewrites base_url to
the credential-less URL and calls credential_from_url(&http_auth, ...)
on it, which credential_clear()s http_auth.

With a username-only URL, http_auth.password was never set, so
init_curl_http_auth() never put CURLOPT_USERNAME/PASSWORD on the handle;
the only auth curl had was the userinfo in the URL. Once the URL is
rewritten, the POST goes out with no credentials, gets 401, and
credential_fill() has nothing to fill from (http_auth was cleared,
no helper, no terminal), hence "could not read Username".

With "user:password@" in the URL the same false redirect happens, but
the push still succeeded in my test - presumably because
init_curl_http_auth() had already set CURLOPT_USERNAME/PASSWORD on the
reused handle before http_auth was cleared.

Possible fix
------------
Compare the URLs without userinfo in update_url_from_redirect() (strip
"user[:pass]@" from the asked-for URL, or from both, before the
strcmp/skip_prefix), so a credential-free effective URL that is
otherwise identical is not treated as a redirect. For a real redirect
on the same origin, keeping the existing http_auth instead of
re-parsing it from a credential-less URL would also avoid losing the
username. I haven't written or tested a patch.

Workaround for users: use "user:token@" instead of "token@" in the URL,
or provide the token through a credential helper.

Thanks,
Daniel Spisak

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [BUG] http: push with token-only URL userinfo fails after libcurl strips creds from CURLINFO_EFFECTIVE_URL
  2026-10-16 22:36 [BUG] http: push with token-only URL userinfo fails after libcurl strips creds from CURLINFO_EFFECTIVE_URL Dan
@ 2026-10-21 11:23 ` Tuomas Ahola
  0 siblings, 0 replies; 2+ messages in thread
From: Tuomas Ahola @ 2026-10-21 11:23 UTC (permalink / raw)
  To: Dan; +Cc: git

Dan <timelord@gmail.com> wrote:

> Hi,
> 
> (Please note this was done with the assistance of Claude, I apologize
> if there are inaccuracies here, Ive tried to go over this and verify
> as much of it as I am capable of. I tried looking at the mailing list
> archives to see if this has already been reported and I didnt see
> anything that looked like it had yet. I can verify that the new
> libcurl behavior absolutely seems to be causing issues from at least
> my own limited vantage point. -Dan)
> 
> Since libcurl stopped returning credentials in CURLINFO_EFFECTIVE_URL
> (curl 8.23.0, commit 7a6bd027d0de "getinfo: make sure
> CURLINFO_EFFECTIVE_URL does not contain creds", CVE-2026-94266; also
> backported to Ubuntu 24.04 as curl 8.5.0-2ubuntu10.16, USN-8932-1),
> pushing over smart HTTP fails when the remote URL carries a username
> but no password, e.g.
> 
>     https://<token>@forge.example/owner/repo.git
> 
> which is a common way for CI tools to pass an access token (Renovate
> does this for Gitea/Forgejo). Fetch/clone keep working; push does not.
> 

Thanks.  Please check if 76524c2604 (http: handle curl stripping creds from
effective url, 2026-09-28) works for you.  The patch is already merged to
'master', and is described in the release notes as:

 * The HTTP transport has been updated to handle changes in recent curl
   versions that strip credentials from the effective URL, preventing
   unnecessary credential prompts during redirects.


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-21 11:23 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-16 22:36 [BUG] http: push with token-only URL userinfo fails after libcurl strips creds from CURLINFO_EFFECTIVE_URL Dan
2026-10-21 11:23 ` Tuomas Ahola

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox