fix: mask an encrypted custom field whatever its type - #895
Merged
blaipr merged 2 commits intoAug 30, 2026
Conversation
The web's custom field partial masked the value inside its `typeName === 'password'` branch alone, and `isEncrypted` is a property of the definition — a checkbox beside the type select, set independently of it. So an encrypted textarea, text, url or color field was decrypted by `ItemTrait::getCustomFieldsForItem()` and then printed in full to anybody who could open the item, whatever CUSTOMFIELD_VIEW_PASS said about them. The API is the sibling that has always had it right: `CustomField::valueFor()` decides on `isValueEncrypted` and never looks at the type, so the same field was withheld from a REST caller and handed over by the web page. The decision is now computed once per field, above the type switch, and used by every branch that prints a value. A password-typed field stays masked whether or not its row was encrypted, and an empty field is left empty rather than masked into a `***` that an edit form would save back as the literal value.
blaipr
deleted the
fix/an-encrypted-custom-field-is-masked-whatever-its-type
branch
August 30, 2026 14:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
aux-customfields.incmasked a custom field's value inside itstypeName === 'password'branchand nowhere else.
isEncryptedis a property of the definition — a checkbox that sits beside thetype select and is set independently of it — so "Encrypted" is on for plenty of fields that are not
typed
password: a textarea holding a recovery phrase, a text field holding an API key, a urlholding a signed one.
ItemTrait::getCustomFieldsForItem()decrypts every such row before the view sees it, so by thetime the partial runs the plaintext is simply sitting in
$field->value. Four of the five branchesprinted it in full —
textarea, the generic<input>thattext,url,number,emailanddateall fall through to, andcolor— to anybody who could open the item, whateverCUSTOMFIELD_VIEW_PASSsaid about them.The API is the sibling that has always had this right:
CustomField::valueFor()decides onisValueEncryptedand never looks at the type, so the same field was withheld from a REST callerand handed over by the web page.
The change
The decision is computed once per field, above the type switch, and used by every branch that
prints a value:
A
password-typed field stays masked whether or not its row was encrypted — that is what thepartial did before, and it is the safer reading of somebody having chosen that type. An empty field
is left empty rather than masked into a
***that an edit form would save back as the literalvalue.
Tests
EncryptedCustomFieldsAreMaskedTestrenders the real partial through a realTemplate, the wayViewpassEscapesTestdoes, because the masking is a property of the template file and of nothingelse. It asserts the mask across all five types, that the value is shown to someone holding the
permission (or the mask assertions would be satisfied by a partial that printed nothing), that an
unencrypted value is left alone, and the two edge cases above.
Mutation-verified: reverting the template fails exactly four of the fifteen —
textarea,text,urlandcolor— whilepasswordkeeps passing, which is the shape of the defect.