You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while implementing #5322 (the field:-prefixed secret leak). Out of that card's scope and not changed by its PR — #5322 was scoped by its dispatch to the field: namespace and the two types the filer measured, and its PR states that narrowness deliberately. Recorded here rather than widened in silently.
Measured
Same probe as #5322 — the real form renderer on the built-in path (no registerAllFields()), main at f2e11ae6f, before and after #5322's fix:
type registry hit rendered type
ui:password true text
secret false text
field:secret false text
All three put the value on screen in clear text. For comparison, the two spellings #5322 does answer:
password true password (native masked input)
field:password false refusal (after #5322 — no input, no value in the DOM)
bare secret — secret is the ObjectQL field type mapFieldTypeToFormType maps to field:password, so an object-derived secret field is safe (it arrives as field:password and A field:-prefixed password / email field renders type="text" when its widget is not registered — a secret shown in clear text #5322 answers it). What is not safe is a hand-authored { name, type: 'secret' } in a standalone FormSchema: secret is not a member of NATIVE_INPUT_FIELD_TYPES and is not a declared metadata type in @object-ui/types either, so it lands on the plain text box.
field:secret — no producer emits it and no widget claims it, so it is nonsense metadata; listed only because it is the third spelling that reaches the same clear-text box.
Reachability, stated honestly
None of the three is emitted by a producer. All three are reachable only through a hand-authored form schema, which is why they were left out of #5322 rather than folded in. That makes this lower severity than #5322 — but the failure mode is identical (a secret rendered in clear text, in a control that looks like it worked), and the hand-authored standalone form is exactly the surface where the author is the producer and no normalizer sits in between.
The question for triage
Not obviously one shape:
A — extend the existing narrow tables. Add secret to NATIVE_INPUT_FIELD_TYPES / SECRET_FIELD_TYPES in packages/components/src/renderers/form/form.tsx, and decide whether a non-field: namespace should have its prefix stripped too. Cheap; leaves the class open for the next spelling.
C — reject at authoring.secret and ui:password are both off-contract as a form fieldtype. A publish-time / validate-time refusal is the contract-first shape and would not need the renderer to grow a table at all.
Related: #5322 (the field: half, fixed), #5254 (the fallback removal that routed these spellings to the default branch).
Search record
search_issues over the namespaced-password / clear-text / secret-field-type keywords; the hits were #5322 (this card's parent finding, open) and #4221 (closed — inline edit on the detail page writing the mask back, a different mechanism). No duplicate.
Found while implementing #5322 (the
field:-prefixed secret leak). Out of that card's scope and not changed by its PR — #5322 was scoped by its dispatch to thefield:namespace and the two types the filer measured, and its PR states that narrowness deliberately. Recorded here rather than widened in silently.Measured
Same probe as #5322 — the real
formrenderer on the built-in path (noregisterAllFields()),mainatf2e11ae6f, before and after #5322's fix:All three put the value on screen in clear text. For comparison, the two spellings #5322 does answer:
Why each one misses
ui:password—renderFieldComponentresolves a form field'stypeonly through thefield:namespace (form 字段type: 'email'经 bare-name 回退落进 SDUI 节点渲染器,field(对象)与max_length一起泄漏到 DOM #5254's ruling), so aui-qualified id resolves nothing and falls to thedefaultarm. There it missesNATIVE_INPUT_FIELD_TYPES, which Afield:-prefixedpassword/emailfield renderstype="text"when its widget is not registered — a secret shown in clear text #5322 keys on thefield:-stripped type only.ui:passwordis registered — as an SDUI node renderer for a top-level{ type: 'email' }-style node — so the registry hit above is real but irrelevant to field resolution.secret—secretis the ObjectQL field typemapFieldTypeToFormTypemaps tofield:password, so an object-derivedsecretfield is safe (it arrives asfield:passwordand Afield:-prefixedpassword/emailfield renderstype="text"when its widget is not registered — a secret shown in clear text #5322 answers it). What is not safe is a hand-authored{ name, type: 'secret' }in a standaloneFormSchema:secretis not a member ofNATIVE_INPUT_FIELD_TYPESand is not a declared metadata type in@object-ui/typeseither, so it lands on the plain text box.field:secret— no producer emits it and no widget claims it, so it is nonsense metadata; listed only because it is the third spelling that reaches the same clear-text box.Reachability, stated honestly
None of the three is emitted by a producer. All three are reachable only through a hand-authored form schema, which is why they were left out of #5322 rather than folded in. That makes this lower severity than #5322 — but the failure mode is identical (a secret rendered in clear text, in a control that looks like it worked), and the hand-authored standalone form is exactly the surface where the author is the producer and no normalizer sits in between.
The question for triage
Not obviously one shape:
secrettoNATIVE_INPUT_FIELD_TYPES/SECRET_FIELD_TYPESinpackages/components/src/renderers/form/form.tsx, and decide whether a non-field:namespace should have its prefix stripped too. Cheap; leaves the class open for the next spelling.field:-prefixedpassword/emailfield renderstype="text"when its widget is not registered — a secret shown in clear text #5322 answered that forfield:only, on the ground thatfield:is the one namespace meaning "field widget"; whetherui:deserves the same treatment or should be rejected outright at the field path is undecided.secretandui:passwordare both off-contract as a form fieldtype. A publish-time / validate-time refusal is the contract-first shape and would not need the renderer to grow a table at all.Related: #5322 (the
field:half, fixed), #5254 (the fallback removal that routed these spellings to the default branch).Search record
search_issuesover the namespaced-password / clear-text / secret-field-type keywords; the hits were #5322 (this card's parent finding, open) and #4221 (closed — inline edit on the detail page writing the mask back, a different mechanism). No duplicate.Generated by Claude Code