So, your original code will be changed to
ClearAll[matM]; makeReference[matM]; withModifiedPart[ matM[i] = ConstantArray[1, {10, 10}]; matM[i][[1, 10]] = 10 ]
What about safety? I would argue that, for this particular case, modifying Part is safe enough. This is because, first, Part is overloaded softly, via UpValues. This means that, when Part is not inside some head which holds arguments, it will execute normally before it would even "think" of a new definition. Now, when it is inside some head which holds arguments, the new definition will only work if that head is Set. Note that no ne rules were added to the Set itself. And since normally, assignments to indexed variables are not allowed anyway, we don't risk breaking some internal behavior.