This is a development preview, not a security-audited production client.
Credentials are stored through the platform secure-storage plugin. Repository-derived persistence is limited to encrypted editor drafts, recent-project IDs and names, transient artifact/attachment/media caches, the AES-256-GCM read cache (read_cache/, including verified terminal-job log tails), explicitly saved encrypted offline repository snapshots (offline_repo/), and opt-in encrypted AI chat history and write journal (ai_history/, ai_write_journal/); see AGENTS.md and CLAUDE.md. An API client belongs to one immutable account session, rejects unexpected API targets, and does not follow credential-bearing redirects.
A self-hosted GitLab behind a company CA or a self-signed certificate can be trusted per instance (#60). After a sign-in fails with an untrusted certificate, the user picks the CA certificate (PEM or DER, at most 64 KiB, no private key) and confirms its SHA-256 fingerprint; it is kept in secure storage under instance_ca.v1.<base64url(instance)>. Only the GitLab clients of that instance trust it, as the platform's default roots plus that certificate (SecurityContext(withTrustedRoots: true)), and an artifact download's redirect only when it stays on the instance's host; other instances, external images, AI providers and the update check keep the default roots, nothing is added to the system or process trust store, and no certificate check is ever bypassed. GitLab.com and its subdomains never take a CA: a refused certificate there is reported as possible interception. No import is offered for a server certificate that has expired or is not yet valid, a CA that does not fix the sign-in is rolled back, and replacing a stored CA shows a warning with the current fingerprint. Android user-installed CAs and network_security_config do not apply to dart:io, which is why the app keeps its own per-instance list. The CA is removed with the last account of its instance, from 我的 › 帳號, or by the start-up sweep when no account of its instance remains. Check the fingerprint with the instance's administrator: a CA trusted here can vouch for any certificate presented by that instance's host.
Android runner generation disables cleartext HTTP and backup, and installs backup/data-extraction exclusions. iOS runner generation adds keychain entitlements. These configurations still require verification on actual supported devices and backup/restore flows.
Never post tokens, private source, private logs, signing keys or account dumps in a public issue or commit. Report vulnerabilities privately to the repository owner using an agreed private channel. No monitored security inbox or disclosure SLA is claimed here.
CI builds use synthetic API fixtures. Preview delivery uses GitLab's short-lived CI_JOB_TOKEN; personal tokens are not embedded in the repository, build, or delivery scripts. Protected-ref CI pipelines build a gitlab-flavor release APK signed with the stable CI preview identity (merge-request pipelines use a discarded ephemeral debug key), while the Google Play build is signed locally with the Play upload key; see docs/ANDROID_SIGNING.md and docs/CI.md.