1. Security Assessment
Security Issues Overview
1.1 Authentication & Authorization
Status: ⚠️Warning
Findings:
- OAuth2 token-based authentication implemented with access and refresh tokens
- Automatic token refresh mechanism on 401 errors via Dio interceptor
- Token-based authentication using
markedeer_oauthpackage - Security concern: Access tokens and refresh tokens stored in plain text in SQLite database (Drift)
- Tokens persist across app restarts without encryption
- Username, email, UID, and login status also stored unencrypted in database
- No token expiration validation on client side
Evidence:
lib/singletons/dio_singleton.dart: OAuth2 token refresh on 401 errors (lines 54-86)lib/states/session_state.dart: Tokens stored directly in database as plain stringsaccessTokenstored directly (lines 82-88)refreshTokenstored directly (lines 90-96)username,uid,emailstored unencrypted (lines 58-80)
lib/database/: Drift/SQLite database used for storagelib/routes/login_route.dart: Login flow stores tokens without encryption (lines 255-260)lib/routes/register_four_route.dart: Registration stores tokens (lines 328-333)
Risk Level: Medium Risk
Recommendation:
- Encrypt sensitive tokens before storing in database using Flutter's secure storage (e.g.,
flutter_secure_storage) - Use Android Keystore/iOS Keychain for storing sensitive credentials
- Implement proper token revocation on logout
- Add token expiration validation on client side
1.2 Data Storage & Encryption
Status: ❌Fail
Findings:
- Critical: Sensitive authentication data stored in plain text in SQLite database
- Access tokens, refresh tokens, usernames, UIDs, and email addresses stored unencrypted
- Drift/SQLite database file accessible on device without encryption
- No encryption at rest for sensitive user data
- Database file can be extracted from device and read directly
- No use of platform secure storage (Android Keystore/iOS Keychain) for sensitive data
- General key-value storage used for all sensitive data without encryption
Evidence:
lib/states/session_state.dart: All sensitive data stored as plain strings in databaseaccessTokenstored directly (line 86)refreshTokenstored directly (line 95)username,uid,emailstored unencrypted (lines 62, 78, 70)
lib/database/database.dart: Drift database implementation without encryption layer- No encryption libraries or secure storage packages in
pubspec.yaml - Database file location: App's data directory (accessible on rooted/jailbroken devices)
lib/database/daos/: General DAO used for key-value storage of sensitive data
Risk Level: High Risk
Recommendation:
- Immediate actions:
- Migrate sensitive data to
flutter_secure_storagepackage - Use Android Keystore and iOS Keychain for credential storage
- Encrypt database file or sensitive columns using SQLCipher
- Remove plain text storage of tokens and credentials
- Short-term:
- Implement database encryption for all sensitive fields
- Use platform-specific secure storage APIs
1.3 Network Security
Status: ❌Fail
Findings:
- Critical: Certificate validation can be disabled via remote configuration
OnlyAllowSuperTankOverrideaccepts invalid SSL certificates for specific host without proper validation- Certificate validation controlled by Firebase Remote Config flag
override_bad_certificates - No certificate pinning implemented
- Hostname validation only checks for exact match ("www.supertankoranjeboven.nl"), not certificate chain validation
AllowAllOverrideclass exists and is used in staging builds, accepting all certificates- Remote config can dynamically enable/disable certificate validation, creating security risk
- Staging build always uses
AllowAllOverride, accepting all certificates regardless of validity
Evidence:
lib/utils/http_overrides.dart:OnlyAllowSuperTankOverrideaccepts certificates for "www.supertankoranjeboven.nl" without proper validation (lines 17-20)AllowAllOverrideaccepts all certificates (lines 7-9) - dangerous pattern
lib/main_prod.dart:HttpOverrides.global = OnlyAllowSuperTankOverride()(line 34)- Remote config can override:
FirebaseRemoteConfig.instance.getBool('override_bad_certificates')(lines 41-44)
lib/main_staging.dart:HttpOverrides.global = AllowAllOverride()(line 38) - Always accepts all certificates- Remote config override also defaults to
AllowAllOverride()(lines 42-45)
- No certificate pinning implementation found
- No SSL/TLS version enforcement
Risk Level: Critical Risk
Recommendation:
- Immediate actions:
- Remove certificate validation override functionality
- Remove
AllowAllOverrideclass entirely or restrict to development builds only - Implement proper certificate pinning using
certificate_pinningor similar package - Remove remote config flag that controls certificate validation
- Enforce strict SSL/TLS validation in production
- Short-term:
- Implement certificate pinning for API endpoints
- Add SSL/TLS version checks (enforce TLS 1.2+)
- Remove ability to disable certificate validation via remote config
- Ensure staging builds use proper certificate validation
1.4 Secrets & Credentials Management
Status: ❌Fail
Findings:
- Critical: Sensitive files including certificates, private keys, and keystores are stored directly in the repository
- Android certificates and keys:
android-assets/supertank.keystore.jks- Android signing keystoreandroid/key.properties- Contains hardcoded path to keystore file
- Apple certificates and keys:
ios-assets/AuthKey_9ZW5QT9Y35 (1).p8- Apple Sign In private key (contains actual private key in repository)ios-assets/ios_push_certificate_pass.rtfand.txt- Push certificate passwords
- Hardcoded path reference to sensitive file in
android/key.properties(line 4) - No centralized secrets management system
- Risk of credentials being exposed in version control history
- No
.gitignoreentries for sensitive directories (android-assets/,ios-assets/)
Evidence:
android-assets/directory contains keystore fileios-assets/directory contains Apple private keys and certificate passwordsios-assets/AuthKey_9ZW5QT9Y35 (1).p8contains private key in repository (PEM format)android/key.propertiesline 4: Hardcoded path to keystore file.gitignoredoes not exclude sensitive directories- Private keys visible in repository
Risk Level: Critical Risk
Recommendation:
- Immediate actions:
- Move all sensitive files to centralized secrets management (e.g., AWS Secrets Manager, HashiCorp Vault, or secure cloud storage)
- Remove sensitive files from repository (after backing up to secure location)
- Add sensitive directories to
.gitignore:android-assets/,ios-assets/ - Rotate all exposed credentials (keystores, private keys)
- Update
android/key.propertiesto reference secrets from secure location or use environment variables - Short-term:
- Implement secrets injection in CI/CD pipeline (Codemagic secrets management)
- Use environment variables or secure file injection for build-time secrets
- Remove hardcoded paths from configuration files
1.5 Code Obfuscation & Reverse Engineering
Status: ✅Pass
Findings:
- Code obfuscation and minification enabled in release builds
minifyEnabled = trueandshrinkResources = truein Android release configuration- ProGuard rules file exists and is used (
proguard-rules.pro) - R8 code shrinking enabled for Android
- Release builds use proper code protection
Evidence:
android/app/build.gradlelines 99-104:
release {
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
android/app/proguard-rules.pro: ProGuard rules configured- Code protection measures in place
Risk Level: Low Risk
Recommendation:
- Consider using Flutter's
--obfuscateflag for additional code protection - Review ProGuard rules to ensure all necessary classes are preserved
- Consider additional string encryption for sensitive API endpoints or keys