Simplifying these methods for iterating through object and modifying string fields
As always simplicity is king. In my opinion you have done a lots of extra effort which might not be necessary.
Let's look at the problem from 10 000 feet high:

You receive an arbitrary object as input
You need to produce a string output where the SN data are masked out

What if you first serialize the data and then mask it?
public static string MaskOut(object toBeMaskedObject,
    string regexPattern = @&quot;\d{6}-?\d{4}[0-9]*&quot;,
    string mask = &quot; XXXXXX-XXXX &quot;)
{
    var serializedData = JsonConvert.SerializeObject(toBeMaskedObject);
    return Regex.Replace(serializedData, regexPattern, mask);
}

And that's it.
I've used the following data structures for testing:
var simpleWithoutSN = new
{
    Desc = &quot;123&quot;,
    Id = 1
};

var simpleWithSN = new
{
    SN = &quot;123456-7891&quot;,
    Id = 1 
};

var nestedWithSN = new
{
    Id = 1,
    Items = new []
    {
        new { SN  = &quot;123456-7891&quot;,},
        new { SN  = &quot;123456-7892&quot;,},
    }
    
};

Console.WriteLine(MaskOut(simpleWithoutSN));
Console.WriteLine(MaskOut(simpleWithSN));
Console.WriteLine(MaskOut(nestedWithSN));

The output will be:
{&quot;Desc&quot;:&quot;123&quot;,&quot;Id&quot;:1}
{&quot;SN&quot;:&quot; XXXXXX-XXXX &quot;,&quot;Id&quot;:1}
{&quot;Id&quot;:1,&quot;Items&quot;:[{&quot;SN&quot;:&quot; XXXXXX-XXXX &quot;},{&quot;SN&quot;:&quot; XXXXXX-XXXX &quot;}]}