Hardcoded cryptographic salt

ID

dart.cryptography.hardcoded_cryptographic_salt

Severity

critical

Remediation Complexity

medium

Remediation Risk

medium

Remediation Effort

medium

Resource

Cryptography

Language

Dart

Description

A cryptographic salt is hardcoded as a literal byte array or string and passed to a key-derivation function (PBKDF2, Argon2, scrypt). A constant salt defeats the purpose of the KDF: every user with the same password derives the same key, enabling precomputed-rainbow-table attacks.

Rationale

Salts serve two purposes: (1) ensure that two users with the same password do not produce the same derived key, defeating cross-user table lookup attacks; and (2) make precomputed attack tables (rainbow-tables) infeasible by expanding the input space beyond what an attacker can practically precompute.

A constant salt eliminates both properties: an attacker who steals a database of (salt, derived_hash) pairs only has to brute-force the password set ONCE for the entire user base, and can build a rainbow table for that single salt offline. For the same memory/CPU budget, this turns a per-user one-week brute-force into a one-shot lookup.

In Dart this appears as a literal byte array passed to Pbkdf2Parameters(saltBytes, iterations, len) in pointycastle or as nonce: const […​] / nonce: utf8.encode("static") on package:cryptography’s `Pbkdf2.deriveKeyFromPassword.

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

class HardcodedSalts {
  void pcStaticSalt() {
    // VULNERABLE: Hardcoded cryptographic salt
    final p1 = Pbkdf2Parameters(Uint8List.fromList([1, 2, 3, 4, 5, 6, 7, 8]), 1000, 32);
    // VULNERABLE: Hardcoded cryptographic salt
    final p2 = Pbkdf2Parameters(utf8.encode("static-salt"), 1000, 32);
    print('$p1 $p2');
  }
}

Remediation

Generate a fresh random salt per user / per derivation using a CSPRNG (typically 16 bytes). Store the salt alongside the derived hash — salts are not secret, just unique.

// Vulnerable
final p = Pbkdf2Parameters(utf8.encode('mysalt'), 100000, 32);

// Fixed
final saltBytes = Uint8List(16);
Random.secure().nextBytes(saltBytes);   // unique random salt
final p = Pbkdf2Parameters(saltBytes, 600000, 32);
// store (saltBytes, derived) together for later verification

Configuration

This detector does not need any configuration.

References

© 2026 Xygeni. All rights reserved