- Shipped
- September 17, 2026 at 3:33 AM UTC
- Author
- Kamo
- Commit
- f1c5d3b
Follow-up to 034378d2, which covered the columns NAMED as ciphertext. Read-only audits of origin/main in every repository found 61 more fields holding credentials with no Jackson guard. Three sets were in live responses: **************** .imapPassword (the encrypted IMAP login): GET /api/email/shared-mailboxes, /my-access, create and update return the entity to any session in the organization. User.password, .seedWords, .securityAnswer, .seedPhraseHash, **************** GET /api/security/org loads the caller's own User, so each org the caller owns serialized its owner in full. **************** the EHR exchange partner list and suspend return the entity. The rest were dormant (every endpoint builds a map or DTO) and one nesting or one returned entity away from publishing: AiProvider.apiKey; **************** **************** .configJson, and **************** which would nest them in the public org body; **************** **************** .password; **************** **************** access/refresh tokens on OrgEmailOAuthTokenEntity, **************** OrgOAuthToken, MemberVoipOAuthToken (+ jwtAssertion), OrgMeetingOAuthTokenEntity, ThirdPartyIntegration (+ webhookSecret); **************** RetailProviderConfig.apiKey, .apiSecret, .accessToken, .webhookSecret; PublicChatVisitor.sessionToken; **************** and the token and code hashes on EmailVerificationToken, PasswordResetToken (tokenShortHash IS the emailed reset code), UserDeviceToken, UserEmailChangeRequest, RecoverySession, PatientPortalSession, PatientPortalInvitation, QuoteShareLink, EsignEnvelopeRecipient, AccountVerificationCode, SmsOtp and MfaRecoveryCode. All are now @JsonIgnore. Checked for each before changing it: no request body binds the entity, nothing reads it with **************** no JSON cache, Redis or NATS transfer carries it, and no client in any repository reads the property. @JsonIgnore rather than WRITE_ONLY, so no request body can plant a password hash. **************** scans every persistent type the way **************** does: a text field whose name says password, secret, apiKey, access/refresh token, jwt, credential, seed words, security answer, private or signing key, or token/code hash, plus six credentials named otherwise, must be @JsonIgnore or WRITE_ONLY. Three names that only look like credentials are listed with the reason (two vault secret NAMES and a webinar join code). Run against origin/main it fails listing exactly the 59 name-matched fields above. A library fix ships per service: emailservice and securityservice are rebuilt with this for the live exposures.