fix(credentials): create the auth profile store owner-only - #5795
Open
ntdatt812 wants to merge 1 commit into
Open
fix(credentials): create the auth profile store owner-only#5795ntdatt812 wants to merge 1 commit into
ntdatt812 wants to merge 1 commit into
Conversation
`fs::write` creates at 0o666 & ~umask -- 0644 under the usual 022 -- and `fs::rename` carries the source mode onto the destination, so auth-profiles.json was world-readable after every save. The mode was never a decision; it was the default nobody overrode, and the credentials module had no hardening at all. On the encrypted-JSON storage path -- the normal state on Linux and on any headless install without a working keyring -- that file holds OAuth token ciphertext, so confidentiality rested entirely on .secret_key being 0600. This is defence-in-depth collapsing to a single control on exactly the installs least likely to have a keyring. write_owner_only() creates with 0o600 already set rather than widening then narrowing, which is the shape tinyhumansai#2360 landed for the secret key in keyring/encrypted_store.rs. It also chmods explicitly, because `.mode()` applies only at creation and an interrupted save can leave a 0644 tmp behind for the next one to reuse -- and rename would carry that through. Windows keeps `fs::write`: there is no mode to set, and the file inherits the ACL of the per-user profile directory. Closes tinyhumansai#5724
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5724.
The defect
write_persisted_lockedwrote the credential store withfs::write, which creates at0o666 & ~umask—0644under the usual022— and thenfs::renamed it into place.renamecarries the source file's mode onto the destination, soauth-profiles.jsonwas world-readable after every save.The mode was never a decision.
grep -rn "set_permissions\|PermissionsExt\|from_mode" src/openhuman/security/credentials/returns nothing: there was no hardening anywhere in the module, and no runtime repair either.What that exposes, and where it actually matters
Not on every install, and I would rather be precise than reach for a severity label:
enc2:ciphertextRow 2 is the normal state on Linux and on any server install without a working keyring. There, confidentiality rested entirely on
.secret_keybeing0600— defence-in-depth collapsing to a single control on exactly the installs least likely to have a keyring.The fix
write_owner_only()creates the file with0o600already set rather than widening then narrowing — the same shape #2360 landed for the secret key inkeyring/encrypted_store.rs:330, whose comment names the goal: "to avoid a TOCTOU race where the file is briefly world-readable".It also chmods explicitly after opening.
.mode()applies only when the file is created, so an interrupted save that left a0644tmp behind would have it reused as-is by the next save — andrenamewould carry that mode straight through to the store. That is the failure this fix would otherwise still have.Windows keeps
fs::write: there is no mode to set, and the file inherits the ACL of the per-user profile directory.Tests
Three cases in a
#[cfg(all(test, unix))]module:a_new_credential_file_is_owner_only— mode is0600, not0644;a_leftover_world_readable_tmp_is_repaired— seeds a0644tmp, asserts the precondition, then asserts the write narrows it. This is the case.mode()alone does not cover;the_contents_are_written_and_truncated— a shorter payload must not leave stale bytes behind, sinceOpenOptionsreplacesfs::write's implicit truncate.Verification note
cargo check -p openhuman --lib→ exit 0, no diagnostic inprofiles.rs;cargo fmtapplied.I could not run the tests: they are
unix-gated and this is a Windows box, where that module does not even compile in. So they are reviewed-by-eye here and will first execute on CI. If you would rather I verify them on Linux before you spend review time, say so and I will find a way to.Not done here
Existing installs stay
0644until their next save, since this fixes the write path rather than repairing on load. #5635 does repairconfig.toml's mode on load; adding the same for the credential store is a reasonable follow-up but a different change, and I did not want to widen this one without asking.