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
The remaining findings of the 2026-09-25 review of internal/keymanager and the root package, none of them a bypass:
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.
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.
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.
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.
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.
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.
The remaining findings of the 2026-09-25 review of
internal/keymanagerand the root package, none of them a bypass:pem.Decodefinds. 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 aCERTIFICATElabel or behindProc-Type: 4,ENCRYPTEDheaders is accepted. Arefresh_secret.keythat is not hex fails withencoding/hex: invalid byte: U+0073 's', which puts a byte of the file into the log.refresh_secret.keyat 0602 or 0620 (replaceable by others) gets no warning while 0644 does.Load, the production path, never looks atKeysDiritself: a 0777 directory loads with no warning.New's load path, the private-key warning onLoad, the world-readable case of the mask (0604), the "only ever tighten" rule forKeysDir(a 0555 directory became 0700), and the choice of the matching staging directory during recovery.Newrefuses withsync parent of keys directory: permission denied, while the same layout loads an existing set fine.KeyStoremay return an emptyKeyID, which registers the current key under""so a token with nokidheader verifies against it; and a previous key whose id equals the current one silently replaced the current key injwt's verification set, so every token the module issued failed its own verification.docs/faq.mdtells an operator hittingErrKeyManagerto delete.authcore, which destroys everyauth/fieldcolumn and API key (docs: three key-material recipes destroy what they are meant to protect #430 fixed three other recipes and not this one), anddocs/containers.mdstill 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.