Skip to content

fix(keymanager): lenient PEM parsing, silent writable files, unpinned controls, and two stale guides #476

Description

@Jaro-c

The remaining findings of the 2026-09-25 review of internal/keymanager and the root package, none of them a bypass:

  1. The PEM decoders accept anything pem.Decode finds. The block type, the headers and whatever follows the first block are ignored, so a file holding two private keys signs with whichever comes first (a secret-manager value with old+new keys concatenated during a rotation), and a PKCS#8 key under a CERTIFICATE label or behind Proc-Type: 4,ENCRYPTED headers is accepted. A refresh_secret.key that is not hex fails with encoding/hex: invalid byte: U+0073 's', which puts a byte of the file into the log.
  2. A writable secret file loads silently. The permission warning masks the read bits only, so refresh_secret.key at 0602 or 0620 (replaceable by others) gets no warning while 0644 does. Load, the production path, never looks at KeysDir itself: a 0777 directory loads with no warning.
  3. Five controls could be removed with the module's suite green: the refresh-secret warning on New's load path, the private-key warning on Load, the world-readable case of the mask (0604), the "only ever tighten" rule for KeysDir (a 0555 directory became 0700), and the choice of the matching staging directory during recovery.
  4. First-run generation fails under a parent with search but no read permission (0711, 0311): the fsync of the parent cannot open it, and New refuses with sync parent of keys directory: permission denied, while the same layout loads an existing set fine.
  5. A KeyStore may return an empty KeyID, which registers the current key under "" so a token with no kid header verifies against it; and a previous key whose id equals the current one silently replaced the current key in jwt's verification set, so every token the module issued failed its own verification.
  6. docs/faq.md tells an operator hitting ErrKeyManager to delete .authcore, which destroys every auth/field column and API key (docs: three key-material recipes destroy what they are meant to protect #430 fixed three other recipes and not this one), and docs/containers.md still says concurrent first start fails about half the time and "is being reworked"; measured today with separate processes, 180 starts without the race detector and 900 with it, none failed.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions