@@ -176,6 +176,7 @@ func (k *keychainStore[T]) Get(ctx context.Context, id store.ID) (store.Secret,
176176 if err != nil {
177177 return nil , err
178178 }
179+ defer clear (rawBlob )
179180 } else {
180181 rawBlob = gc .CredentialBlob
181182 }
@@ -377,45 +378,58 @@ func (k *keychainStore[T]) Filter(ctx context.Context, pattern store.Pattern) (m
377378 return nil , mapWindowsCredentialError (err )
378379 }
379380
380- gcAttributes := mapFromWindowsAttributes (gc .Attributes )
381-
382- // Determine the raw UTF-16 blob before safelyCleanMetadata strips chunkCountKey.
383- var rawBlob []byte
384- if countStr , ok := gcAttributes [chunkCountKey ]; ok {
385- count , err := strconv .Atoi (countStr )
386- if err != nil {
387- return nil , fmt .Errorf ("invalid chunk count %q: %w" , countStr , err )
388- }
389- rawBlob , err = k .readChunks (id , count )
390- if err != nil {
391- return nil , err
392- }
393- } else {
394- rawBlob = gc .CredentialBlob
381+ secret , err := k .loadSecret (ctx , id , gc )
382+ if err != nil {
383+ return nil , err
395384 }
385+ secrets [id ] = secret
386+ }
396387
397- safelyCleanMetadata (gcAttributes )
388+ return secrets , nil
389+ }
398390
399- secret := k .factory (ctx , id )
400- if err := secret .SetMetadata (gcAttributes ); err != nil {
401- return nil , err
402- }
391+ // loadSecret fetches, decodes, and zeroes the raw blob for id, then
392+ // returns a fully populated Secret. rawBlob is zeroed only when it was
393+ // allocated by readChunks (chunked path); gc.CredentialBlob is not ours.
394+ func (k * keychainStore [T ]) loadSecret (ctx context.Context , id store.ID , gc * wincred.GenericCredential ) (store.Secret , error ) {
395+ gcAttributes := mapFromWindowsAttributes (gc .Attributes )
403396
404- decoder := unicode .UTF16 (unicode .LittleEndian , unicode .IgnoreBOM ).NewDecoder ()
405- blob , _ , err := transform .Bytes (decoder , rawBlob )
397+ var (
398+ rawBlob []byte
399+ chunked bool
400+ )
401+ if countStr , ok := gcAttributes [chunkCountKey ]; ok {
402+ count , err := strconv .Atoi (countStr )
406403 if err != nil {
407- return nil , err
404+ return nil , fmt . Errorf ( "invalid chunk count %q: %w" , countStr , err )
408405 }
409-
410- if err := secret .Unmarshal (blob ); err != nil {
411- clear (blob )
406+ rawBlob , err = k .readChunks (id , count )
407+ if err != nil {
412408 return nil , err
413409 }
414- clear (blob )
415- secrets [id ] = secret
410+ chunked = true
411+ } else {
412+ rawBlob = gc .CredentialBlob
413+ }
414+ if chunked {
415+ defer clear (rawBlob )
416416 }
417417
418- return secrets , nil
418+ safelyCleanMetadata (gcAttributes )
419+
420+ secret := k .factory (ctx , id )
421+ if err := secret .SetMetadata (gcAttributes ); err != nil {
422+ return nil , err
423+ }
424+
425+ decoder := unicode .UTF16 (unicode .LittleEndian , unicode .IgnoreBOM ).NewDecoder ()
426+ blob , _ , err := transform .Bytes (decoder , rawBlob )
427+ if err != nil {
428+ return nil , err
429+ }
430+ defer clear (blob )
431+
432+ return secret , secret .Unmarshal (blob )
419433}
420434
421435func mapWindowsCredentialError (err error ) error {
0 commit comments