security: harden dictation, telemetry, tools, file perms, and supply chain#1335
Open
r3dbars wants to merge 2 commits into
Open
security: harden dictation, telemetry, tools, file perms, and supply chain#1335r3dbars wants to merge 2 commits into
r3dbars wants to merge 2 commits into
Conversation
…chain Audit-driven security hardening across six areas. No behavior change for normal use; all changes are defensive. Dictation / paste (Sources/UI/Overlay, Sources/Support): - HIGH: re-verify the paste target is still frontmost immediately before Auto Enter posts Return, so a stray Enter is never submitted into a window that stole focus during the auto-enter delay. Skips + logs (counts only). - Clipboard restore now best-effort clears resident dictation text when the restore guard fails, instead of leaving it on the pasteboard. - Synthetic Cmd+V / Return use a private CGEventSource so they don't inherit physically-held modifiers. - Harden meeting-title filename sanitizer (strip leading dots / all-dots). Telemetry (Sources/Observability, Sources/UI/Shared): - Route support-diagnostic Sentry extras through a positive key allowlist (drops the free-text reliability blob and uncaught interpolated keys), matching the captureObservabilityEvent contract. - Hard length cap on the free-text-capable `reason` Sentry tag. - Make unused allowlist-bypassing capture(error:)/capture(message:) inert. Companion tools (Tools/*): - Cap full-file transcript reads (16 MB shared CaptureFileLimits) across MCP, CLI, and CaptureKit to remove an unbounded-read local-DoS. File permissions (Sources/*): - Set umask(0o077) at app init so created files are owner-only by default, closing the write-then-chmod TOCTOU window; add posixPermissions to explicit createFile sites as belt-and-suspenders. Supply chain / docs: - Assert mlx-swift-lm resolved revision matches the pin in build-deps.sh. - Document eSpeak NG GPL-3.0 corresponding-source offer. - Document MCP trust model, appcast hosting, screen-capture audio-only intent, and disable-library-validation rationale in SECURITY.md. Verification: privacy-leak-sweep PASS; nightly-security-check 98/100 (only a pre-existing unrelated automation.toml finding). Swift build/tests require macOS and must run in CI — not runnable in this Linux environment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QXiZDoQn4mmK2mKuz7R4w7
…yContext The support-diagnostic hardening added the allowlist + test but left the `latest_reliability_packet` free-text blob being built in `sentryContext` itself, so its new raw-context assertion (SupportDiagnosticsBundleTests:183) failed in CI. Remove the emission at the source — `reliability_packet_count` already carries the coarse signal, and the human-readable diagnostics text (built separately and redacted) still summarizes recent packets. The downstream allowlist remains as defense-in-depth. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QXiZDoQn4mmK2mKuz7R4w7
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.
Why
A deep security audit of the app surfaced a set of defensive gaps — none critical, but worth closing. This PR fixes the actionable findings from that audit. The app's security posture was already strong (local-first, owner-only files, Sparkle EdDSA, HTTPS-only telemetry with allowlists, mature nightly checks); these are hardening changes on top of that.
Product Impact
dictation/meetings/agent artifacts/docs only(all four, defensively)dictation reliability+release ops+agent workflowWhat changed
Dictation / paste
DictationSessionController.performAutoEnterIfNeeded). Skips and logs counts/bundle-id only.CGEventSourceso they don't inherit physically-held modifiers.Telemetry (Sentry)
SupportDiagnosticsBundle, dropping the free-text reliability blob and interpolatedroute_*/runtime_*/storage_*keys the sensitive-key fragment list didn't catch — matching thecaptureObservabilityEventcontract instead of relying on key-drop + regex alone.reasondiagnostic tag before redaction.capture(error:)/capture(message:)made inert no-ops (no callers in the tree).Companion tools
CaptureFileLimits.maxTranscriptBytesacross MCP, CLI, and CaptureKit, removing an unboundedString(contentsOf:)local-DoS. Each call site honors its existing not-found/empty/throw contract on over-cap.File permissions
umask(0o077)at appinitso every created file is owner-only by default, closing the write-then-chmod TOCTOU window (coversData.write(.atomic)temp files too); addedposixPermissions: 0o600to explicitcreateFilesites as belt-and-suspenders. ExistingrestrictToOwnerOnly/chmod calls retained.Supply chain / docs
build-deps.shnow asserts the resolvedmlx-swift-lmrevision matches the pin (mirrors the WhisperKit revision check), failing loudly on drift.THIRD_PARTY_LICENSES.md: explicit eSpeak NG GPL-3.0-or-later corresponding-source offer.SECURITY.md: documented the MCP trust model (launch == full read), appcast hosting/trust roots, screen-capture audio-only intent, and thedisable-library-validationrationale + removal tracking.How I checked it
python3 scripts/ops/privacy-leak-sweep.py→ PASS (all leak classes, 0 findings)python3 scripts/ops/nightly-security-check.py→ 98/100 (secret_scan 25/25, observability_privacy 25/25, release_integrity 20/20, entitlements_and_signing 15/15; the only finding is a pre-existing, unrelated missing localautomation.toml)bash -n scripts/entrypoints/build-deps.sh→ OKconfig/security/nightly-security-manifest.json)EventReporter.capture,DictationPasteTarget.matchesCurrentFrontmostApp,dictationContext(extra:)) and that the ToolsPackage.swifttest-target product references resolvebash build.sh --no-open/bash run-tests.sh/bash run-integration-smoke.sh/swift test— not runnable here: this environment is Linux with no Swift toolchain and the targets are macOS-only (platforms: [.macOS(.v14)]). These need to run in macOS CI before merge.Risk Review
build-deps.shassertion is additive; no version/appcast changesNotes
Tests were added/extended in existing registered files (
ClipboardRestoringTextPasterTests,SentryEventPolicyTests,SupportDiagnosticsBundleTests) and the Tools package test targets — noTests/FastTests.manifestchanges were required.Out of scope / deliberately not changed (flagged in the audit, not code-fixable here):
disable-library-validation+ sandbox-off remain (required by the MLX/WhisperKit/CoreML stack; mitigated by Developer-ID + notarization) — now documented and tracked.com.justinbetker.draftleft as-is (changing it has signing/TCC/Sparkle-identity consequences).🤖 Generated with Claude Code
https://claude.ai/code/session_01QXiZDoQn4mmK2mKuz7R4w7
Generated by Claude Code