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_oauth package
  • 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 strings
    • accessToken stored directly (lines 82-88)
    • refreshToken stored directly (lines 90-96)
    • username, uid, email stored unencrypted (lines 58-80)
  • lib/database/: Drift/SQLite database used for storage
  • lib/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 database
    • accessToken stored directly (line 86)
    • refreshToken stored directly (line 95)
    • username, uid, email stored 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_storage package
  • 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
  • OnlyAllowSuperTankOverride accepts 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
  • AllowAllOverride class 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:
    • OnlyAllowSuperTankOverride accepts certificates for "www.supertankoranjeboven.nl" without proper validation (lines 17-20)
    • AllowAllOverride accepts 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 AllowAllOverride class entirely or restrict to development builds only
  • Implement proper certificate pinning using certificate_pinning or 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 keystore
    • android/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.rtf and .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 .gitignore entries for sensitive directories (android-assets/, ios-assets/)

Evidence:

  • android-assets/ directory contains keystore file
  • ios-assets/ directory contains Apple private keys and certificate passwords
  • ios-assets/AuthKey_9ZW5QT9Y35 (1).p8 contains private key in repository (PEM format)
  • android/key.properties line 4: Hardcoded path to keystore file
  • .gitignore does 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.properties to 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 = true and shrinkResources = true in 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.gradle lines 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 --obfuscate flag for additional code protection
  • Review ProGuard rules to ensure all necessary classes are preserved
  • Consider additional string encryption for sensitive API endpoints or keys