How can we prevent a masked variable from echoing if its value has been changed
In short: you can't if someone with access is determined to do so.
Masking is not meant to prevent developers with access to control CI steps from revealing secrets through jobs. It is meant to prevent disclosure by accident. There are endless ways that a value could be exfiltrated through the job output it would be impossible to cover them all.
If you wanted to prevent the base64 representation of the secret from being shown, you can register that value as another masked variable, but it must be done in advance.
Shouldn't masked variables show [MASKED] even the value is different from its original value ?
Good arguments could be made that GitLab should mask some common variations of masked variables, such as base64, url-encoded, backwards, etc. Other CI services (Travis CI for example) do this.
However, this would still be ONLY for the purposes of accidental disclosure.
For example, another way I've seen developers accidentally reveal secrets is by using curl with the -v flag.
script:
- curl -v https://myusername:${SECRET_JAMES_BOND}@myhost.example.com/secret
In the above example, the output of curl will show (in part) an output like:
> Authorization: Basic bXl1c2VybmFtZTpzZWNyZXQ=
So, if GitLab also masked base64 variations of a password, it would have prevented this accidental disclosure.
But like I mentioned, there's endless ways to output a secret: url-encoding, Caesar cipher, rot-N (rot16, rot24, rot32, etc) or even custom ways like just echoing each character one line at a time, potentially in reverse order.
So, really, you can only realistically prevent accidents, not malicious exfiltration by a user with access to execute code in a job.