This document describes the security posture of MyDeck and the design decisions that affect how the app handles sensitive data, network communication, and untrusted content.
If you discover a security vulnerability, please report it privately by opening a GitHub Security Advisory rather than a public issue.
MyDeck authenticates with the Readeck server using the OAuth 2.0 Device Authorization Grant flow. The app never handles or stores the user's Readeck password directly. OAuth tokens are stored in EncryptedSharedPreferences using AES-256 (SIV for keys, GCM for values), backed by the Android Keystore.
The default release build enforces HTTPS-only communication:
cleartextTrafficPermitted="false"in the network security config- Only system-trusted certificate authorities are accepted
- OAuth requires HTTPS by design
For users running Readeck on a local network or behind a private CA, two opt-in build flags are available. These are disabled by default and require a custom build:
ALLOW_INSECURE_HTTP_RELEASE— permits cleartext HTTP connections (forhttp://Readeck instances without TLS)ALLOW_USER_CA_RELEASE— trusts user-installed certificate authorities (for HTTPS servers signed by a private CA)
These flags are documented in .github/workflows/release.yml and are never enabled in the standard GitHub release builds.
- OAuth tokens are stored in
EncryptedSharedPreferences(AES-256-GCM), not in plainSharedPreferencesor the local database. - User-facing preferences (theme, typography, sync settings) are stored in unencrypted
SharedPreferencessince they contain no sensitive data. - The Room database stores bookmark metadata and content. It does not contain authentication credentials.
MyDeck uses two distinct WebView contexts with different security profiles:
- Loads app-owned HTML templates from local assets, populated with server-extracted article content
- JavaScript is enabled to support in-article search, highlight/annotation interaction, and image lightbox functionality
- Two
@JavascriptInterfacebridges are registered for image tap handling and annotation interaction - Content is sandboxed within the app's asset domain; no external navigation occurs from this WebView
- Loads the original source URL when the user selects "View web page" from the overflow menu
- JavaScript and DOM storage are enabled so that modern websites render correctly
- No
@JavascriptInterfacebridges are registered on this WebView — it has no privileged access to app internals - No cookies are shared between this WebView and the app's authenticated API communication
- File access is disabled by default (Android WebView default)
- This WebView is functionally equivalent to opening the URL in a browser, but kept in-app for reading continuity
The original web page WebView enables JavaScript because most modern websites require it to render. Disabling JavaScript makes video sites (YouTube, Vimeo) and many article sites non-functional, with no visible indication of why the page is broken. Since this WebView has no privileged bridges, no access to app credentials, and no cookie sharing with the authenticated API layer, the risk profile is comparable to opening the same URL in any browser — which the user can already do from the bookmark details screen.
- Release builds use R8 code shrinking and obfuscation
dependenciesInfois excluded from the APK (includeInApk = false) and AAB (includeInBundle = false)- GitHub Actions release workflows use pinned action versions
- Bookmark content is synced from the user's own Readeck server and stored locally in Room
- No analytics, telemetry, or crash reporting services are included
- No data is sent to third-party services; all communication is between the app and the user's Readeck server