Skip to content

Values export ("download values") leaves several secret fields unredacted #3456

Description

@aweingarten

Summary

The values export produced by the console Download values feature (#1517) is named values-redacted-<timestamp>.yaml and masks most secrets as <redacted>, but several secret-bearing fields pass through in cleartext. Because the -redacted filename signals the file is safe to share, these leak in practice — they get pasted into tickets, chats, and screen-shares on the assumption that redaction was complete.

Verified against an exported values-redacted-*.yaml from an apl-core v4.14.1 instance. No values are reproduced here.

Fields redacted correctly (for contrast)

otomi.adminPassword, kms.sops.age.privateKey, apps.cert-manager.customRootCA{,Key}, apps.harbor.* secrets, apps.keycloak.idp.clientSecret, apps.loki.adminPassword, apps.oauth2-proxy.config.cookieSecret, apps.gitea.*Password, obj.provider.linode.secretAccessKey, etc. — all <redacted>.

Fields NOT redacted (the bug)

  1. users[].initialPassword — cleartext for every user, including platform admins. Never masked.

  2. teamConfig.<team>.settings.passwordinconsistent: teamConfig.admin.settings.password is <redacted>, but the same field on a non-admin team (e.g. teamConfig.<otherTeam>.settings.password) is cleartext. Strongly suggests the redaction path special-cases the admin team (or the first team) rather than matching the field by shape, so every additional team's password slips through.

  3. obj.provider.linode.accessKeyId — cleartext. Its paired secretAccessKey is redacted, but an access-key ID is half the credential and shouldn't be exposed either.

Why it matters

  • initialPassword on isPlatformAdmin: true users is a direct path to admin access if those passwords were not rotated after first login.
  • The per-team settings.password inconsistency means the redaction gives false assurance: an operator who confirms the admin password is masked reasonably assumes all of them are.

Suggested fix

Redact by field identity across all list/map entries rather than by fixed top-level paths — apply the same masking to users[].initialPassword and teamConfig.*.settings.password (all teams, not just admin), and treat obj.provider.linode.accessKeyId as sensitive alongside its secret key. A denylist keyed on leaf names (password, initialPassword, accessKeyId, secret*, *Key, …) applied recursively would close all three at once and be robust to new teams/users.

Repro

  1. Configure an instance with ≥1 non-admin team and ≥1 platform-admin user.
  2. Console → Download values.
  3. Grep the resulting values-redacted-*.yaml for initialPassword:, the non-admin team's settings.password:, and accessKeyId: — all appear in cleartext.

Environment: apl-core v4.14.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    communityIssue made by a community memberon holdWaiting for another party to do something

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions