Skip to content

Prevent secret values from leaking into the DOM when concealed#17024

Merged
rak-phillip merged 3 commits into
rancher:masterfrom
adifsgaid:fix-secret-values-exposed-on-select-all
Apr 20, 2026
Merged

Prevent secret values from leaking into the DOM when concealed#17024
rak-phillip merged 3 commits into
rancher:masterfrom
adifsgaid:fix-secret-values-exposed-on-select-all

Conversation

@adifsgaid
Copy link
Copy Markdown
Contributor

@adifsgaid adifsgaid commented Mar 26, 2026

Summary

Fixes #17023

Occurred changes and/or fixed issues

  • Secret values concealed with the dotsfont CSS approach were still present as plaintext in the DOM, allowing text selection + copy to expose actual secret values
  • KeyValue.vue: replaced the TextAreaAutoGrow with .conceal class with a static placeholder <div> that renders bullet characters and uses user-select: none when valueConcealed is true
  • DetailText.vue: when concealed, renders a static bullet placeholder instead of the real value. JSON values skip CodeMirror entirely when concealed

Technical notes summary

  • The fix ensures real secret values are never rendered in the DOM when concealed — the dotsfont visual masking is replaced with a static placeholder that contains only bullet characters
  • The CopyToClipboard button still copies the real value (this is intentional — it requires an explicit user click)
  • The input type="password" fallback path is unchanged as it already uses native browser masking

Areas or cases that should be tested

  • Browser used for local testing: Chrome
  • View an Opaque secret with the "Hide Sensitive Data" preference enabled (default)
  • Select all text on the page (Ctrl+A) and copy — should NOT contain real values
  • Mouse-select text on the value area and copy — should NOT contain real values
  • Click the eye icon to reveal values — should show the real values
  • Click the Copy button — should copy the real value to clipboard
  • Toggle the global "Hide Sensitive Data" preference off and verify values show normally
  • Test with JSON-formatted secret values
  • Test in both light and dark mode

Areas which could experience regressions

  • Secret detail view (Data tab) for all secret types (Opaque, Basic Auth, SSH, TLS, Registry)
  • KeyValue component used elsewhere with valueConcealed prop
  • DetailText component used for displaying concealed values

Screenshot/Video

Checklist

  • The PR is linked to an issue and the linked issue has a Milestone, or no issue is needed
  • The PR has a Milestone
  • The PR template has been filled out
  • The PR has been self reviewed
  • The PR has a reviewer assigned
  • The PR has automated tests or clear instructions for manual tests and the linked issue has appropriate QA labels, or tests are not needed
  • The PR has reviewed with UX and tested in light and dark mode, or there are no UX changes
  • The PR has been reviewed in terms of Accessibility
  • The PR has considered, and if applicable tested with, the three Global Roles Admin, Standard User and User Base

The conceal mechanism used a custom dot font to visually mask secret
values, but the actual plaintext remained in the DOM. Selecting text
(Ctrl+A or mouse selection) and copying would expose the real secret
values.

Replace the dot-font approach with a static placeholder that never
renders real values in the DOM when concealed. Add unit tests for
both KeyValue and DetailText components to verify secret values
are not present in rendered HTML when concealment is active.
@adifsgaid adifsgaid force-pushed the fix-secret-values-exposed-on-select-all branch from 3538ff8 to 038473c Compare March 26, 2026 14:39
@gaktive gaktive requested a review from rak-phillip March 26, 2026 18:15
@rak-phillip rak-phillip added this to the v2.15.0 milestone Apr 8, 2026
@rak-phillip rak-phillip self-assigned this Apr 8, 2026
Copy link
Copy Markdown
Member

@rak-phillip rak-phillip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adifsgaid thanks for raising this PR and the associated issue. We might also be able to remove the dots font with this change now that we no longer render every character as a dot by swapping the font family. I think we can do the following now:

  • remove shell/assets/styles/fonts/_dots.scss
  • delete the dots import in shell/assets/styles/app.scss

Comment thread shell/components/form/KeyValue.vue
Comment thread shell/components/DetailText.vue Outdated
Move bullet placeholder characters from template content to CSS
::before pseudo-elements so they never render in the DOM tree,
making them purely presentational and unselectable by default.
@adifsgaid
Copy link
Copy Markdown
Contributor Author

adifsgaid commented Apr 16, 2026

@rak-phillip applied both nits, bullets are now in CSS ::before and the templates are empty.

Also went ahead and removed the dots font. LabeledInput in rancher-components was the only other consumer of the .conceal class for multiline-password masking (used in googleoauth.vue). Replaced it with -webkit-text-security: disc which does the same thing natively without the custom font, if anything else needs to be done feel free to add further comments !

Delete the dots font entirely since concealed values no longer rely
on font swapping. Migrate LabeledInput multiline-password masking
to -webkit-text-security: disc which is natively supported.
@adifsgaid adifsgaid requested a review from rak-phillip April 20, 2026 08:51
Copy link
Copy Markdown
Member

@rak-phillip rak-phillip left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adifsgaid excellent, thanks for the follow up and for contributing to Rancher!

@rak-phillip rak-phillip merged commit c173594 into rancher:master Apr 20, 2026
38 checks passed
@adifsgaid adifsgaid deleted the fix-secret-values-exposed-on-select-all branch April 21, 2026 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Concealed secret values can be copied as plaintext via text selection

2 participants