* [PATCH 1/2] wincred: avoid memory corruption when erasing a credential
2026-07-16 14:27 [PATCH 0/2] Some wincred fixes Johannes Schindelin via GitGitGadget
@ 2026-07-16 14:27 ` Johannes Schindelin via GitGitGadget
2026-07-16 14:27 ` [PATCH 2/2] wincred: prevent silent credential loss when storing OAuth tokens Johannes Schindelin via GitGitGadget
2026-07-16 18:34 ` [PATCH 0/2] Some wincred fixes Junio C Hamano
2 siblings, 0 replies; 4+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2026-07-16 14:27 UTC (permalink / raw)
To: git; +Cc: Johannes Schindelin, Johannes Schindelin
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(-)
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
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH 2/2] wincred: prevent silent credential loss when storing OAuth tokens
2026-07-16 14:27 [PATCH 0/2] Some wincred fixes Johannes Schindelin via GitGitGadget
2026-07-16 14:27 ` [PATCH 1/2] wincred: avoid memory corruption when erasing a credential Johannes Schindelin via GitGitGadget
@ 2026-07-16 14:27 ` Johannes Schindelin via GitGitGadget
2026-07-16 18:34 ` [PATCH 0/2] Some wincred fixes Junio C Hamano
2 siblings, 0 replies; 4+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2026-07-16 14:27 UTC (permalink / raw)
To: git; +Cc: Johannes Schindelin, Johannes Schindelin
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(-)
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
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH 0/2] Some wincred fixes
2026-07-16 14:27 [PATCH 0/2] Some wincred fixes Johannes Schindelin via GitGitGadget
2026-07-16 14:27 ` [PATCH 1/2] wincred: avoid memory corruption when erasing a credential Johannes Schindelin via GitGitGadget
2026-07-16 14:27 ` [PATCH 2/2] wincred: prevent silent credential loss when storing OAuth tokens Johannes Schindelin via GitGitGadget
@ 2026-07-16 18:34 ` Junio C Hamano
2 siblings, 0 replies; 4+ messages in thread
From: Junio C Hamano @ 2026-07-16 18:34 UTC (permalink / raw)
To: Johannes Schindelin via GitGitGadget; +Cc: git, Johannes Schindelin
"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.
>
> 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
^ permalink raw reply [flat|nested] 4+ messages in thread