When shields have no pattern(s) applied, they use the damage value to determine color instead of the Base field in BlockEntityTag. This field is also used to track the durability of the shield, which has two effects:
- Changing the durability of the shield (by taking damage or repairing it) changes the color
- Crafting a new shield creates one that has lost 0 to 15 points of durability
A simple fix would be to always add the BlockEntityTag when crafting a new shield and always set the damage value to 0, and for shields without BlockEntityTag (e.g. obtained through /give), to always display their color as black.