Skip to content

Settings raw store and known-keys list return credential values unmasked #293

Description

@antosubash

worktree-hifi-pages taught the module-settings editor to hide credentials by value as well as by
name — embeds_credential marks a DSN with a password in its authority as secret
(modules/settings/settings/_secrets.py:33-55), and _module_settings masks value, default and
env reading on that rule (modules/settings/settings/_module_settings.py:139-175). The other two
screens that show the same data never got the rule.

  • The raw store shows everything. SettingService._out masks only exact matches against
    SENSITIVE_KEYS, which is the single-entry frozenset {"host.secret_key"}
    (modules/settings/settings/service.py:28-38, modules/settings/settings/constants.py:52).
    list_filtered feeds /admin/settings/store through it
    (modules/settings/settings/service.py:82-107, modules/settings/settings/endpoints/views.py:96-116),
    so a DB override named smtp_password, or any override holding a
    postgresql://user:pw@host/db, renders in clear text in the table and in the edit form.
    Pre-existing, not introduced here.
  • known_keys._from_definition builds an unmasked default.
    modules/settings/settings/known_keys.py:47-61 hard-codes "is_secret": False and passes
    definition.default straight through, where the sibling _from_field masks it. The New-override
    suggestion list renders that default verbatim
    (modules/settings/settings/pages/components/KeyField.tsx:47-52). Inert today because no
    registry declaration ships a credential default, but it is one declaration away.
  • embeds_credential only inspects str. modules/settings/settings/_secrets.py:50 returns
    False for anything else, so a list- or dict-typed field holding DSNs would be shown. No such
    field exists today.
  • _strip_mask_sentinels drops the mask literal on any field.
    modules/settings/settings/endpoints/module_api.py:40-53 filters on the sentinel value alone,
    so a non-secret string field whose real value happens to be eight bullets is silently not
    saved. Documented in the docstring; implausible but unbounded.
  • Dead payload fields. known_keys ships module and description on every suggestion
    (modules/settings/settings/known_keys.py:32-35, :52-53); the KnownKey interface declares
    them (modules/settings/settings/pages/components/KeyField.tsx:10-11) and nothing renders
    either.
  • Store pagination is typed str in the schema. browse's page/per_page are declared
    str so a bookmarked link never 422s
    (modules/settings/settings/endpoints/views.py:82-83,
    modules/settings/settings/browse_query.py:41-48). The intent is right, but the OpenAPI schema
    now advertises them as strings.

What would fix it: run the store's read path through the same is_secret_field / embeds_credential
pair _module_settings uses instead of the SENSITIVE_KEYS allowlist (with the existing
placeholder-echo guard extended to cover it, so an admin who saves an untouched form does not write
dots over a real value), mask _from_definition's default on the same rule, widen embeds_credential
to walk lists and dict values, and drop the two unused KnownKey fields.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions