iOS security hardening: Keychain, clipboard, https-only, tmp file protection - #2
Merged
Merged
Conversation
…https-only server, tmp file protection Follow-up from the iOS/Swift security review of the nimshare app (no backend changes): - Keychain (Keychain.swift): store the JWT with kSecAttrAccessibleWhenUnlockedThisDeviceOnly instead of AfterFirstUnlock, so a live session token is not decryptable while the device is locked. ThisDeviceOnly is kept (no iCloud sync / backup leak). - Clipboard: copy API tokens (ApiTokensView) and revealed license keys (KeyStoreView, KeyStoreLicensesView) with .localOnly + a 60 s expiry, so secrets don't sync via Universal Clipboard and auto-clear. Share-link URLs are unchanged (not secrets). - Server config (ServerConfigView): accept https:// only; reject cleartext http:// (which ATS already blocks at runtime) with a clear message. - Downloads (TmpFile): sanitize the server-provided filename (strip path separators / traversal) and set FileProtectionType.completeUnlessOpen on the temp directory. Deferred (separate follow-up): optional biometric (Face ID) app-lock and a client-side token max-age — a UX feature rather than a surgical hardening tweak. Note: iOS/UIKit can't be compiled on this Linux runner; changes are surgical and were hand-reviewed — build verification happens in Xcode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MjfiPG6J7tTFm1dFx5zYmh
mnimtz
marked this pull request as ready for review
August 5, 2026 04:51
mnimtz
added a commit
that referenced
this pull request
Aug 7, 2026
Marcus's Test (basf.de): Willkommenstext ok, aber kein Logo + eigenes Logo weg + "Bereitgestellt mit NimShare" links statt mittig. - Logo (#2): basf.de leitet auf www.basf.com um; relative Logo-URLs wurden gegen die URSPRUNGS-Domain aufgelöst → falscher Host → kein Logo. Jetzt gegen die FINALE URL nach Redirects (resp.RequestMessage.RequestUri) aufgelöst. - Eigenes Logo (#4): ResolveThemeAsync mergt jetzt — Link-Vorlage überlagert nur gesetzte Felder, leere (z.B. kein Kundenlogo) fallen aufs Instanz/Personal- Branding zurück. Ohne Link-Vorlage byte-genau wie bisher. - Footer (#3): "Bereitgestellt mit NimShare" auf der Folder-Landing zentriert. Lokal mit .NET 8 gebaut: 0 Fehler. VERSION 1.12.1 → 1.12.2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Summary
Follow-up from the iOS/Swift security review of the nimshare app. Backend is untouched — these are client-side hardening fixes only. The app was already solid (tokens in Keychain, no WebView, no TLS bypass,
Authorizationstripped on redirect, ATS at secure defaults, zero secret logging); this closes the remaining at-rest / clipboard gaps.Fixes
🟠 Medium — Keychain accessibility hardened (
Keychain.swift)JWT session token was stored with
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly→ decryptable while the device is locked. NowkSecAttrAccessibleWhenUnlockedThisDeviceOnly(the app only touches the token in the foreground).ThisDeviceOnlykept → no iCloud sync / backup leak.🟠 Medium — Secrets no longer leak via the shared/Universal clipboard
API tokens (
ApiTokensView) and revealed license keys (KeyStoreView,KeyStoreLicensesView) were copied viaUIPasteboard.general.string→ readable by any app + synced to other Apple devices. Now copied with.localOnly: true+ a 60 s.expirationDate. Share-link URLs are left as-is (they're shareable links, not secrets).🟢 Low — Server config is HTTPS-only (
ServerConfigView)The server-URL field accepted
http://. ATS already blocks cleartext at runtime, but it's now rejected in the input with a clear message (defense-in-depth against a future ATS exception).🟢 Low — Download hardening (
TmpFile)Server-provided filenames are sanitized (path separators /
..stripped — defense-in-depth; writes were already sandboxed to tmp), and the temp download dir is set toFileProtectionType.completeUnlessOpen.Deferred (flagged, not in this PR)
LAContextflow + locked overlay), so it deserves its own change rather than a rushed edit — happy to do it as a focused follow-up.What was checked and is clean
Token in Keychain (not UserDefaults); password never persisted (AutoFill); no hardcoded secrets; no
URLSessionDelegateTLS bypass;Authorizationheader stripped on redirect to Blob SAS; ATS secure defaults; no deep-link/URL-scheme surface; no WebView (QuickLook + AVPlayer); zeroprint/NSLog/os_log; TOTP secret never stored.🤖 Generated with Claude Code
https://claude.ai/code/session_01MjfiPG6J7tTFm1dFx5zYmh
Generated by Claude Code