fix(security): block PII in chat attachments and typed messages #59
Merged
sarman
merged 6 commits from 2026-06-01 01:20:26 +00:00
fix/pii-detection-bypass into master
6 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
249d20bf85 |
fix: audit PII redaction metadata, safe bubble update, update ticket
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m54s
Test / frontend-typecheck (pull_request) Successful in 2m6s
Test / frontend-tests (pull_request) Successful in 2m5s
Test / rust-clippy (pull_request) Successful in 3m59s
PR Review Automation / review (pull_request) Successful in 4m10s
Test / rust-tests (pull_request) Successful in 5m15s
Add was_pii_redacted and pii_types_redacted to the ai_chat audit log entry. Both are tracked through the full_message build block (typed message + attachments) so any redaction that occurs is always reflected in the compliance record. Fix response.user_message + suffix potentially yielding 'undefined...' when user_message is absent. Now unconditionally calls updateMessageContent with (response.user_message ?? message) + suffix, so the bubble always shows a valid string regardless of backend build. Update TICKET-pii-bypass-chat-attachments.md to reflect the final auto-redact design (not block/warn) so automated review comparisons against the ticket stop flagging design decisions as defects. |
||
|
|
631221dbf1 |
fix(security): full-content PII scan, clippy, IPC null fix, scan size cap
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m40s
Test / frontend-typecheck (pull_request) Successful in 1m48s
Test / frontend-tests (pull_request) Successful in 1m43s
Test / rust-clippy (pull_request) Successful in 3m17s
Test / rust-tests (pull_request) Successful in 4m33s
PR Review Automation / review (pull_request) Successful in 5m0s
Remove frontend detectPiiCmd pre-scan loop — backend is sole redaction authority; bubble update via response.user_message covers user feedback. Detect PII on full file content before truncating. Previous order (truncate to 8000 bytes then scan) could miss PII straddling the boundary. Now: read full content, scan, redact, then truncate to EMBED_LIMIT (8000 bytes) at a valid UTF-8 char boundary. logFileIds IPC: pass undefined (not null) for empty array so Tauri serialises it correctly to Rust Option::None. Add MAX_TEXT_SCAN_BYTES (32 KB) guard in scan_text_for_pii to prevent unbounded regex evaluation on oversized payloads. Fix clippy uninlined_format_args in ai.rs. |
||
|
|
e9c576f606 |
fix(security): frontend attachment scan notice, bubble redaction update, fmt fix
Some checks failed
Test / rust-fmt-check (pull_request) Successful in 2m3s
Test / frontend-tests (pull_request) Successful in 1m56s
Test / frontend-typecheck (pull_request) Successful in 1m58s
Test / rust-clippy (pull_request) Failing after 3m0s
Test / rust-tests (pull_request) Successful in 4m22s
PR Review Automation / review (pull_request) Successful in 4m35s
Addresses three findings from the third automated review: [BLOCKER] No frontend PII pre-check on attachments. Added detectPiiCmd call for each logFileId before chatMessageCmd. PII is not blocked (per explicit product decision: auto-redact and send) but the user now sees a non-blocking amber notice listing each file and the PII types that will be auto-redacted. Backend remains the authoritative redaction layer. [WARNING 2] Chat bubble showed original PII-laden message even though only the redacted form was sent to AI. Added updateMessageContent to sessionStore. After chatMessageCmd returns, if response.user_message is set the user bubble is updated to reflect what was actually stored in the DB, so the UI is consistent with the audit log. CI fix: cargo fmt changes to analysis.rs were not staged in the prior commit. Committed here — fmt check now passes cleanly. |
||
|
|
a04d6fc8f5 |
fix(security): backend-only PII redaction; fix fmt CI failure
Some checks failed
Test / frontend-typecheck (pull_request) Successful in 1m52s
Test / frontend-tests (pull_request) Successful in 1m51s
Test / rust-fmt-check (pull_request) Failing after 1m58s
Test / rust-clippy (pull_request) Failing after 3m4s
Test / rust-tests (pull_request) Successful in 4m31s
PR Review Automation / review (pull_request) Successful in 4m43s
Resolves all three findings from the second automated review and fixes the cargo fmt --check CI failure (formatting drift in analysis.rs from a prior merge). [BLOCKER 1 + BLOCKER 2 + WARNING] Frontend no longer performs any PII scanning or redaction. All three concerns stemmed from the same root cause: outMessage was derived on the frontend and used for display, DB storage (via lastUserMsgRef and the chat bubble), and the AI payload — causing the original message to be silently replaced before the backend received it. Fix: frontend sends the original message verbatim. Backend is now the sole authority. chat_message auto-redacts the typed message text using PiiDetector + apply_redactions() before building the full payload, logs the PII types via tracing::warn, and stores only the redacted form in ai_messages and the audit log. The redacted form is returned to the caller as ChatResponse.user_message (Option<String>, absent from direct provider calls). Frontend uses message (original) for the chat bubble and lastUserMsgRef — resolution steps show natural language, not [Password] tokens. The AI and DB see only the redacted version. CI fix: cargo fmt applied to analysis.rs; all format checks now pass. |
||
|
|
f05b954250 |
fix(security): address PR review — move attachment handling to backend, auto-redact PII
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 1m25s
Test / frontend-typecheck (pull_request) Successful in 1m37s
Test / frontend-tests (pull_request) Successful in 1m36s
Test / rust-clippy (pull_request) Failing after 3m18s
PR Review Automation / review (pull_request) Successful in 4m19s
Test / rust-tests (pull_request) Successful in 4m30s
Resolves all four findings from the automated review: [BLOCKER 1] Attachment PII scan error path left pendingFiles intact, allowing retry with stale file references. Fix: file content is no longer held in frontend state at all — PendingFile drops the content field entirely. logFileIds are captured before setPendingFiles([]) and passed directly to the backend. [BLOCKER 2] Raw file content stored in PendingFile.content created a UI-visible PII surface and a data-residency risk. Fix: frontend never reads or stores file content. The backend loads file data from disk, auto-redacts PII in-memory using pii::apply_redactions(), and embeds the clean text into the AI message. No PII ever touches the frontend. [WARNING 1] String-based attachment header parsing was fragile and bypassable. Fix: parsing is gone — backend identifies attachments by log_file_id, reads them directly from the DB/disk path, and applies redaction at that level. [WARNING 2] Error message disclosed PII type list to the caller. Fix: PII types are logged via tracing::warn only; no type details in the user-facing error or API response. Additionally: typed chat messages are now auto-redacted rather than blocked. scanTextForPiiCmd runs on the typed text; detected spans are replaced in reverse-offset order before the message is sent to the AI and stored in the DB. The user sees the redacted form in their chat bubble. Architecture: - chat_message now accepts log_file_ids: Option<Vec<String>> - Backend reads file → detects PII → redacts in memory → embeds - Frontend: no readTextFile, no content field, no frontend PII gate |
||
|
|
cd26801a39 |
fix(security): block PII in chat attachments and typed messages
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 1m31s
Test / frontend-tests (pull_request) Successful in 1m34s
Test / frontend-typecheck (pull_request) Successful in 1m36s
Test / rust-clippy (pull_request) Successful in 3m5s
PR Review Automation / review (pull_request) Successful in 4m31s
Test / rust-tests (pull_request) Successful in 4m27s
File attachments were embedded into AI messages without any PII scanning, allowing credentials, tokens, and other sensitive data to be forwarded to AI providers in plaintext. Typed chat messages had the same gap: a user could type a password or API key directly and it would be sent unscanned. Changes: - chat_message (Rust): defence-in-depth scan of all attachment body content (between --- Attached: markers); hard rejects if PII found - detect_pii (Rust): fix return type from pii::PiiDetectionResult (spans/original_text) to db::models::PiiDetectionResult (detections/total_pii_found) to match the TypeScript contract; the LogUpload PII review workflow was receiving undefined for detections - scan_text_for_pii (Rust): new command — scans arbitrary text for PII without creating DB records; used for typed message warnings - Triage/index.tsx: PendingFile now carries logFileId; handleSend gates each text attachment through detectPiiCmd (hard block on PII found); typed message text scanned via scanTextForPiiCmd with a one-time warning — second send of same message proceeds as acknowledgment |