Hardcoded credential / secret in Dart source

ID

dart.auth.hardcoded_credentials

Severity

high

Remediation Complexity

medium

Remediation Risk

high

Remediation Effort

medium

Resource

Auth

Language

Dart

Description

A credential / secret is embedded as a string literal in source: a top-level / class-field const / final / String declaration named api_key, access_token, refresh_token, client_secret, password, bearer, etc. assigned a non-trivial literal. The Dart obfuscator does not protect string literals — anyone with the binary has this credential.

Rationale

Cossack Labs documented that flutter build --obfuscate obfuscates symbols but NOT string literals: the literal bytes survive intact in the shipped Dart snapshot and are recoverable with analyze_snapshot, blutter, or a hex editor. Hardcoded credentials in Flutter source must therefore be considered public — equivalent to publishing them on GitHub.

Impact varies by credential type:

  • API keys (Firebase, Stripe, Sentry DSN, Google Maps, AWS): let the attacker call the upstream API with your billing account; abuse can run into thousands of dollars before detection, and the API key may grant access to user data.

  • OAuth client secrets: enable token impersonation against your backend.

  • JWT signing secrets: total authentication forgery.

  • Bearer / Basic auth literals in headers: replay against the target service.

The rule also matches an Authorization: Bearer <long-string> header literal — a common shape in copy-pasted curl examples that survive into committed code.

The following code illustrates a vulnerable pattern detected by this rule:

// Positive cases for dart.hardcoded_credentials.

class Config {
  // VULNERABLE: Hardcoded credential / secret in Dart source
  static const String apiKey = "sk_live_abcdef1234567890";
}

Remediation

Load secrets at runtime from flutter_secure_storage, fetch them from an authenticated backend after sign-in, or — for build-time configuration — inject via --dart-define / --dart-define-from-file and read with String.fromEnvironment. For values that genuinely need to ship with the app (a public API key with documented usage limits), confirm with the upstream service that public exposure is acceptable.

// Vulnerable
static const String apiKey = "sk_live_abcdef1234567890";
static const String clientSecret = "OAuth-Secret-1234567890";
final headers = {"Authorization": "Bearer eyJhbGc..."};

// Fixed: build-time injection
static const String apiKey = String.fromEnvironment('STRIPE_API_KEY');
// build with: flutter build apk --dart-define=STRIPE_API_KEY=sk_live_...

// Fixed: runtime from secure storage
const storage = FlutterSecureStorage();
final token = await storage.read(key: 'access_token');

Configuration

This detector does not need any configuration.

References

© 2026 Xygeni. All rights reserved