VYPR
High severityNVD Advisory· Published Jan 14, 2025· Updated Apr 15, 2026

CVE-2024-53263

CVE-2024-53263

Description

Git LFS is a Git extension for versioning large files. When Git LFS requests credentials from Git for a remote host, it passes portions of the host's URL to the git-credential(1) command without checking for embedded line-ending control characters, and then sends any credentials it receives back from the Git credential helper to the remote host. By inserting URL-encoded control characters such as line feed (LF) or carriage return (CR) characters into the URL, an attacker may be able to retrieve a user's Git credentials. This problem exists in all previous versions and is patched in v3.6.1. All users should upgrade to v3.6.1. There are no workarounds known at this time.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/git-lfs/git-lfsGo
>= 0.1.0, <= 3.0.0
github.com/git-lfs/git-lfs/v3Go
>= 3.0.0, < 3.6.13.6.1

Patches

2
0345b6f816e6

creds/creds.go: reject LF bytes in credential data

https://github.com/git-lfs/git-lfsChris DarrochNov 27, 2024via ghsa
3 files changed · +74 6
  • creds/creds.go+10 3 modified
    @@ -58,21 +58,25 @@ func (c Creds) IsMultistage() bool {
     	return slices.Contains([]string{"1", "true"}, FirstEntryForKey(c, "continue"))
     }
     
    -func (c Creds) buffer() *bytes.Buffer {
    +func (c Creds) buffer() (*bytes.Buffer, error) {
     	buf := new(bytes.Buffer)
     
     	buf.Write([]byte("capability[]=authtype\n"))
     	buf.Write([]byte("capability[]=state\n"))
     	for k, v := range c {
     		for _, item := range v {
    +			if strings.Contains(item, "\n") {
    +				return nil, errors.Errorf(tr.Tr.Get("credential value for %s contains newline: %q", k, item))
    +			}
    +
     			buf.Write([]byte(k))
     			buf.Write([]byte("="))
     			buf.Write([]byte(item))
     			buf.Write([]byte("\n"))
     		}
     	}
     
    -	return buf
    +	return buf, nil
     }
     
     type CredentialHelperContext struct {
    @@ -338,7 +342,10 @@ func (h *commandCredentialHelper) exec(subcommand string, input Creds) (Creds, e
     	if err != nil {
     		return nil, errors.New(tr.Tr.Get("failed to find `git credential %s`: %v", subcommand, err))
     	}
    -	cmd.Stdin = input.buffer()
    +	cmd.Stdin, err = input.buffer()
    +	if err != nil {
    +		return nil, errors.New(tr.Tr.Get("invalid input to `git credential %s`: %v", subcommand, err))
    +	}
     	cmd.Stdout = output
     	/*
     	   There is a reason we don't read from stderr here:
    
  • creds/creds_test.go+18 3 modified
    @@ -25,7 +25,8 @@ func TestCredsBufferFormat(t *testing.T) {
     
     	expected := []string{"capability[]=authtype\n", "capability[]=state\n"}
     
    -	buf := creds.buffer()
    +	buf, err := creds.buffer()
    +	assert.NoError(t, err)
     	assertCredsLinesMatch(t, expected, buf)
     
     	creds["protocol"] = []string{"https"}
    @@ -34,7 +35,8 @@ func TestCredsBufferFormat(t *testing.T) {
     	expectedPrefix := strings.Join(expected, "")
     	expected = append(expected, "protocol=https\n", "host=example.com\n")
     
    -	buf = creds.buffer()
    +	buf, err = creds.buffer()
    +	assert.NoError(t, err)
     	assert.True(t, strings.HasPrefix(buf.String(), expectedPrefix))
     	assertCredsLinesMatch(t, expected, buf)
     
    @@ -43,11 +45,24 @@ func TestCredsBufferFormat(t *testing.T) {
     	expected = append(expected, "wwwauth[]=Basic realm=test\n")
     	expected = append(expected, "wwwauth[]=Negotiate\n")
     
    -	buf = creds.buffer()
    +	buf, err = creds.buffer()
    +	assert.NoError(t, err)
     	assert.True(t, strings.HasPrefix(buf.String(), expectedPrefix))
     	assertCredsLinesMatch(t, expected, buf)
     }
     
    +func TestCredsBufferProtect(t *testing.T) {
    +	creds := make(Creds)
    +
    +	// Always disallow LF characters
    +	creds["protocol"] = []string{"https"}
    +	creds["host"] = []string{"one.example.com\nhost=two.example.com"}
    +
    +	buf, err := creds.buffer()
    +	assert.Error(t, err)
    +	assert.Nil(t, buf)
    +}
    +
     type testCredHelper struct {
     	fillErr    error
     	approveErr error
    
  • t/t-credentials-protect.sh+46 0 added
    @@ -0,0 +1,46 @@
    +#!/usr/bin/env bash
    +
    +. "$(dirname "$0")/testlib.sh"
    +
    +ensure_git_version_isnt $VERSION_LOWER "2.3.0"
    +
    +export CREDSDIR="$REMOTEDIR/creds-credentials-protect"
    +setup_creds
    +
    +# Copy the default record file for the test credential helper to match the
    +# hostname used in the Git LFS configurations of the tests.
    +cp "$CREDSDIR/127.0.0.1" "$CREDSDIR/localhost"
    +
    +begin_test "credentials rejected with line feed"
    +(
    +  set -e
    +
    +  reponame="protect-linefeed"
    +  setup_remote_repo "$reponame"
    +  clone_repo "$reponame" "$reponame"
    +
    +  contents="a"
    +  contents_oid=$(calc_oid "$contents")
    +
    +  git lfs track "*.dat"
    +  printf "%s" "$contents" >a.dat
    +  git add .gitattributes a.dat
    +  git commit -m "add a.dat"
    +
    +  # Using localhost instead of 127.0.0.1 in the LFS API URL ensures this URL
    +  # is used when filling credentials rather than the Git remote URL, which
    +  # would otherwise be used since it would have the same scheme and hostname.
    +  gitserver="$(echo "$GITSERVER" | sed 's/127\.0\.0\.1/localhost/')"
    +  testreponame="test%0a$reponame"
    +  git config lfs.url "$gitserver/$testreponame.git/info/lfs"
    +
    +  GIT_TRACE=1 git lfs push origin main 2>&1 | tee push.log
    +  if [ "0" -eq "${PIPESTATUS[0]}" ]; then
    +    echo >&2 "fatal: expected 'git lfs push' to fail ..."
    +    exit 1
    +  fi
    +  grep "batch response: Git credentials for $gitserver.* not found" push.log
    +  grep "credential value for path contains newline" push.log
    +  refute_server_object "$testreponame" "$contents_oid"
    +)
    +end_test
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.