Volume XXII, number 279Tuesday, October 6, 2026Latest message 41 minutes ago

The Git List

News and archive of git@vger.kernel.org, since April 2005

patch, 2 partsSome wincred fixes

4 messages between Jul 16, 2026 and Jul 16, 2026, from Johannes Schindelin via GitGitGadget, Junio C Hamano.

Plain Markdown or JSON for tools and agents. Diffs are folded; open one to read it.

Johannes Schindelin via GitGitGadgetJul 16, 2026, 14:27 UTC on lore

These were rolled out as part of the security fix release Git for Windows v2.55.0(3).

Johannes Schindelin (2):
  wincred: avoid memory corruption when erasing a credential
  wincred: prevent silent credential loss when storing OAuth tokens
 contrib/credential/wincred/git-credential-wincred.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2182%2Fdscho%2Fwincred-fixes-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2182/dscho/wincred-fixes-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2182
-- 
gitgitgadget
Johannes Schindelin via GitGitGadgetJul 16, 2026, 14:27 UTC in reply to Johannes Schindelin via GitGitGadget on lore

[PATCH 1/2] wincred: avoid memory corruption when erasing a credential

From: Johannes Schindelin <johannes.schindelin@gmx.de>

The earlier d22a488482 (wincred: avoid memory corruption, 2025-11-17) repaired only get_credential(); match_cred_password() has the same defect and is reached on `git credential reject`. When Git asks the helper to erase a stored credential whose password was supplied by the caller, the helper copies the candidate's password into a freshly allocated buffer for comparison. That copy overruns the allocation by one WCHAR of NUL, which on uninstrumented Windows manifests as process termination with status 0xC0000374. Because the helper can die before reaching CredDeleteW(), `git credential reject` masks the failure and the rejected credential remains stored.

CredentialBlobSize is documented as a byte count, so for an N-WCHAR blob it equals N * sizeof(WCHAR). The pre-fix code allocated that many bytes and asked wcsncpy_s to copy N wide characters, but wcsncpy_s always appends a terminating NUL WCHAR, writing one WCHAR past the allocation. The destination-capacity argument was also passed in bytes rather than in WCHAR elements as the API requires, so the safe-CRT runtime never rejected the copy.

See GHSA-rxqw-wxqg-g7hw.
Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 contrib/credential/wincred/git-credential-wincred.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
Show changes to contrib/credential/wincred/git-credential-wincred.c +4 −4
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 73c2b9b72a..190bbccdf9 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -121,10 +121,10 @@ static int match_part_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
 
 static int match_cred_password(const CREDENTIALW *cred) {
 	int ret;
-	WCHAR *cred_password = xmalloc(cred->CredentialBlobSize);
-	wcsncpy_s(cred_password, cred->CredentialBlobSize,
-		(LPCWSTR)cred->CredentialBlob,
-		cred->CredentialBlobSize / sizeof(WCHAR));
+	size_t wlen = cred->CredentialBlobSize / sizeof(WCHAR);
+	WCHAR *cred_password = xmalloc((wlen + 1) * sizeof(WCHAR));
+	wcsncpy_s(cred_password, wlen + 1,
+		(LPCWSTR)cred->CredentialBlob, wlen);
 	ret = !wcscmp(cred_password, password);
 	free(cred_password);
 	return ret;
-- 
gitgitgadget
Johannes Schindelin via GitGitGadgetJul 16, 2026, 14:27 UTC in reply to Johannes Schindelin via GitGitGadget on lore

[PATCH 2/2] wincred: prevent silent credential loss when storing OAuth tokens

From: Johannes Schindelin <johannes.schindelin@gmx.de>

When `git credential approve` hands the wincred helper a password together with an `oauth_refresh_token`, the OAuth branch of `store_credential()` writes one WCHAR past the allocation while formatting both fields into a single `CredentialBlob`. On Windows this trips heap verification and tears the helper down with status `0xC0000374`; `approve` masks the failure, so the credential the user meant to save never reaches `CredWriteW()` and the next session prompts for it again.

The bug has the same shape as the one fixed in the previous commit: the allocation leaves no room for the terminating NUL, and the `sizeOfBuffer` argument to `_snwprintf_s()` is a byte count where the API expects a WCHAR count, which lets the safe-CRT runtime write the terminator out of bounds.

Apply the same remedy d22a488482 (wincred: avoid memory corruption, 2025-11-17) applied in `get_credential()`: allocate `(wlen + 1) * sizeof(WCHAR)` bytes and pass `wlen + 1` as the destination capacity in WCHARs.

This closes the second of the two heap writes tracked under GHSA-rxqw-wxqg-g7hw.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 contrib/credential/wincred/git-credential-wincred.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Show changes to contrib/credential/wincred/git-credential-wincred.c +2 −2
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 190bbccdf9..22eb27ca31 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -208,8 +208,8 @@ static void store_credential(void)
 
 	if (oauth_refresh_token) {
 		wlen = _scwprintf(L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token);
-		secret = xmalloc(sizeof(WCHAR) * wlen);
-		_snwprintf_s(secret, sizeof(WCHAR) * wlen, wlen, L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token);
+		secret = xmalloc((wlen + 1) * sizeof(WCHAR));
+		_snwprintf_s(secret, wlen + 1, wlen, L"%s\r\noauth_refresh_token=%s", password, oauth_refresh_token);
 	} else {
 		secret = _wcsdup(password);
 	}
-- 
gitgitgadget
Junio C HamanoJul 16, 2026, 18:34 UTC in reply to Johannes Schindelin via GitGitGadget on lore

Re: [PATCH 0/2] Some wincred fixes

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com> writes:

> These were rolled out as part of the security fix release Git for Windows
> v2.55.0(3).
Thanks.  Let me merge it down fast.
Show 13 quoted lines
>
> Johannes Schindelin (2):
>   wincred: avoid memory corruption when erasing a credential
>   wincred: prevent silent credential loss when storing OAuth tokens
>
>  contrib/credential/wincred/git-credential-wincred.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
>
>
> base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2182%2Fdscho%2Fwincred-fixes-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2182/dscho/wincred-fixes-v1
> Pull-Request: https://github.com/gitgitgadget/git/pull/2182

Back to recent threads

[PATCH 0/2] Some wincred fixes | The Git List