security: protect local data at rest (issue #146) #172

Open
jabber.developer2 wants to merge 1 commits from fix/data-at-rest-hardening into master
Collaborator

Closes #146

Implements all three work streams; every finding was re-verified against current master before implementation.

T03 — keep secrets out of profanity.log (REQ-DAR-03, REQ-LOG-06)

New redact_secrets() helper masks the content of SASL auth/response/challenge/success, (XEP-0077, MUC) and (XEP-0078) elements. Applied in the libstrophe logger and the stderr-to-log bridge. Input is normalised with g_utf8_make_valid() first so invalid UTF-8 cannot make redaction fail open.
_add_to_db() no longer logs decrypted message bodies or the full INSERT statement.
T07 — owner-only permissions (REQ-AUTH-01)

chmod 0600 on chatlog.db after open (journal/WAL inherit) and on OTR keys.txt/fingerprints.txt after every write. Parent directories were already 0700; this is defense in depth.
T08 — integrity before trust (REQ-RES-02, REQ-CRY-06)

PRAGMA quick_check(1) gates every chatlog.db open. On failure the DB stays closed, the user gets a one-time console warning, and the session continues without history.
OMEMO aesgcm downloads now decrypt into a 0600 tempfile next to the target and rename it into place only after the GCM tag verifies. Previously the plaintext was written straight to the destination and — worse — the open-command hook ran even when decryption failed; both are fixed, unverified output is always deleted.
Tests: unit tests for the redaction helper (8 cases incl. legacy-auth digest and invalid UTF-8); AES-256-GCM roundtrip plus tampered-tag/tampered-ciphertext tests (src/omemo/crypto.c is now linked into unittests under BUILD_OMEMO); functional test planting a corrupt chatlog.db and asserting the client warns and stays up.

Verification: clean -Werror build; unittests 649/649; functional suite 152 OK. The one failing functional test, ai_providers_lists_defaults, is broken on master independently of this branch — it expects the pre-chat-completions string "Available AI providers:" while master prints "Configured providers:"; fix incoming separately. Manually confirmed in a live client log: legacy-auth password appears as [REDACTED], chatlog.db is created -rw-------.

Deliberately out of scope: the issue's optional CI grep for plaintext-in-logs; SASL2 (XEP-0388) element names (libstrophe 0.14 does not emit them); the raw XML console (/xmlconsole) intentionally keeps showing live unredacted traffic — it is an ephemeral debug view, not a persistent log.

Closes #146 Implements all three work streams; every finding was re-verified against current master before implementation. T03 — keep secrets out of profanity.log (REQ-DAR-03, REQ-LOG-06) New redact_secrets() helper masks the content of SASL auth/response/challenge/success, <password> (XEP-0077, MUC) and <digest> (XEP-0078) elements. Applied in the libstrophe logger and the stderr-to-log bridge. Input is normalised with g_utf8_make_valid() first so invalid UTF-8 cannot make redaction fail open. _add_to_db() no longer logs decrypted message bodies or the full INSERT statement. T07 — owner-only permissions (REQ-AUTH-01) chmod 0600 on chatlog.db after open (journal/WAL inherit) and on OTR keys.txt/fingerprints.txt after every write. Parent directories were already 0700; this is defense in depth. T08 — integrity before trust (REQ-RES-02, REQ-CRY-06) PRAGMA quick_check(1) gates every chatlog.db open. On failure the DB stays closed, the user gets a one-time console warning, and the session continues without history. OMEMO aesgcm downloads now decrypt into a 0600 tempfile next to the target and rename it into place only after the GCM tag verifies. Previously the plaintext was written straight to the destination and — worse — the open-command hook ran even when decryption failed; both are fixed, unverified output is always deleted. Tests: unit tests for the redaction helper (8 cases incl. legacy-auth digest and invalid UTF-8); AES-256-GCM roundtrip plus tampered-tag/tampered-ciphertext tests (src/omemo/crypto.c is now linked into unittests under BUILD_OMEMO); functional test planting a corrupt chatlog.db and asserting the client warns and stays up. Verification: clean -Werror build; unittests 649/649; functional suite 152 OK. The one failing functional test, ai_providers_lists_defaults, is broken on master independently of this branch — it expects the pre-chat-completions string "Available AI providers:" while master prints "Configured providers:"; fix incoming separately. Manually confirmed in a live client log: legacy-auth password appears as [REDACTED], chatlog.db is created -rw-------. Deliberately out of scope: the issue's optional CI grep for plaintext-in-logs; SASL2 (XEP-0388) element names (libstrophe 0.14 does not emit them); the raw XML console (/xmlconsole) intentionally keeps showing live unredacted traffic — it is an ephemeral debug view, not a persistent log.
jabber.developer2 added 1 commit 2026-07-21 09:24:05 +00:00
security: protect local data at rest (issue #146)
All checks were successful
CI Code / Check spelling (pull_request) Successful in 15s
CI Code / Check coding style (pull_request) Successful in 26s
CI Code / Linux (debian) (pull_request) Successful in 5m3s
CI Code / Linux (arch) (pull_request) Successful in 6m25s
CI Code / Linux (ubuntu) (pull_request) Successful in 8m1s
CI Code / Code Coverage (pull_request) Successful in 9m27s
b63a9d29f8
T03 — keep secrets out of profanity.log:
- new redact_secrets() helper (common.c) masks the content of SASL
  auth/response/challenge/success and <password> elements; applied in
  the libstrophe logger (_xmpp_file_logger) and the stderr-to-log
  bridge (REQ-DAR-03, REQ-LOG-06)
- _add_to_db() no longer logs decrypted message bodies or the full
  INSERT statement (REQ-DAR-03)

T07 — owner-only permissions on key material and history (REQ-AUTH-01):
- chmod 0600 on chatlog.db after open (journal/WAL files inherit)
- chmod 0600 on OTR keys.txt and fingerprints.txt after every write
- parent dirs are already 0700 (create_dir); this is defense in depth

T08 — integrity before trust:
- PRAGMA quick_check(1) gates every chatlog.db open; on failure the
  DB stays closed, the user is warned once in the console and the
  session continues without history (REQ-RES-02)
- OMEMO aesgcm downloads decrypt into a 0600 tempfile next to the
  target and rename it into place only after the GCM tag verifies;
  the open-command hook no longer runs on failed decryption
  (REQ-CRY-06)

Tests: redact_secrets unit tests; AES-256-GCM roundtrip and
tampered-tag/ciphertext unit tests (crypto.c now linked into
unittests under BUILD_OMEMO); functional test planting a corrupt
chatlog.db and asserting graceful degradation.

Closes #146
All checks were successful
CI Code / Check spelling (pull_request) Successful in 15s
Required
Details
CI Code / Check coding style (pull_request) Successful in 26s
Required
Details
CI Code / Linux (debian) (pull_request) Successful in 5m3s
Required
Details
CI Code / Linux (arch) (pull_request) Successful in 6m25s
Required
Details
CI Code / Linux (ubuntu) (pull_request) Successful in 8m1s
Required
Details
CI Code / Code Coverage (pull_request) Successful in 9m27s
Required
Details
This pull request is blocked because it's outdated.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin fix/data-at-rest-hardening:fix/data-at-rest-hardening
git checkout fix/data-at-rest-hardening
Sign in to join this conversation.
No description provided.