SecureString
System.String
C#
.NET
Programming

How to convert SecureString to System.String?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

You can convert a SecureString to a System.String, but the moment you do, you lose most of the protection that SecureString was trying to provide. That is why the real answer is not just "how," but also "how briefly and under what constraints."

The usual conversion uses Marshal to copy the secure contents into unmanaged memory, turn that memory into a managed string, and then zero out the unmanaged buffer immediately. Even with that cleanup, the resulting System.String still exists as plain text in managed memory.

The Standard Conversion Pattern

Here is the common .NET approach:

csharp
1using System;
2using System.Runtime.InteropServices;
3using System.Security;
4
5public static class SecureStringHelpers
6{
7    public static string ToPlainString(SecureString secure)
8    {
9        if (secure == null)
10        {
11            throw new ArgumentNullException(nameof(secure));
12        }
13
14        IntPtr ptr = IntPtr.Zero;
15        try
16        {
17            ptr = Marshal.SecureStringToGlobalAllocUnicode(secure);
18            return Marshal.PtrToStringUni(ptr)!;
19        }
20        finally
21        {
22            if (ptr != IntPtr.Zero)
23            {
24                Marshal.ZeroFreeGlobalAllocUnicode(ptr);
25            }
26        }
27    }
28}

This is the standard pattern because it at least ensures the temporary unmanaged buffer is wiped and freed after use.

What Each Step Does

The important calls are:

  • 'SecureStringToGlobalAllocUnicode, which copies the secure contents into unmanaged memory,'
  • 'PtrToStringUni, which creates the managed string,'
  • 'ZeroFreeGlobalAllocUnicode, which zeroes and frees the unmanaged buffer.'

That cleanup matters, but it only protects the unmanaged staging area. Once the secret becomes a managed string, it is immutable and cannot be scrubbed in the same reliable way.

Why This Is Still Risky

Converting to System.String means the secret now exists in plain text in managed memory. Garbage collection decides when that memory goes away, and you cannot force the runtime to overwrite every copy immediately.

That is why conversion should be treated as a last-resort compatibility step for APIs that insist on string, not as a normal secure-storage workflow.

Keep the Plain Text Scope Tiny

If you must convert, do it as late as possible and keep the resulting string alive for as little time as possible:

csharp
1string password = SecureStringHelpers.ToPlainString(securePassword);
2try
3{
4    LegacyApi.Login(username, password);
5}
6finally
7{
8    password = string.Empty;
9}

Reassigning the variable does not erase the original string from memory immediately, but it does reduce the chance of accidental reuse or logging later in the method.

Modern .NET Caveat

Modern .NET guidance is more cautious about SecureString than older guidance was. It is not a magical shield, and many developers overestimate what it can guarantee.

The practical takeaway is simple:

  • do not convert unless an API forces you to,
  • prefer APIs that accept safer alternatives when possible,
  • do not assume the converted string remains secure just because it originated from a SecureString.

If a library offers an overload that accepts credentials through a callback, token object, or platform credential store, that is usually preferable to forcing the secret through a plain managed string.

Common Pitfalls

  • Converting to string too early and keeping the plain-text value around longer than necessary.
  • Forgetting to zero the unmanaged buffer in the finally block.
  • Logging the converted string during debugging.
  • Assuming SecureString still protects the value after it becomes a System.String.
  • Using conversion casually when the call site could have been redesigned to avoid it.

Summary

  • The normal conversion path uses Marshal.SecureStringToGlobalAllocUnicode and Marshal.PtrToStringUni.
  • Always wipe the unmanaged buffer with Marshal.ZeroFreeGlobalAllocUnicode.
  • The resulting System.String is plain text in managed memory.
  • Convert only when compatibility requires it, and keep that plain-text scope as small as possible.
  • 'SecureString reduces exposure in some scenarios, but conversion largely removes that advantage.'

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.