Use of a broken or risky cryptographic mode of operation (ECB)

ID

dart.cryptography.weak_encryption_mode_of_operation

Severity

critical

Remediation Complexity

medium

Remediation Risk

medium

Remediation Effort

medium

Resource

Cryptography

Language

Dart

Description

AES (or another block cipher) is used in ECB mode. ECB encrypts identical plaintext blocks to identical ciphertext, leaking the structure of the input and enabling block-shuffling attacks.

Rationale

The Electronic Codebook (ECB) mode encrypts each block of plaintext independently with the same key. Two equal plaintext blocks therefore always produce equal ciphertext blocks — the classic "ECB penguin" demonstrates this visually. Attackers exploit this for:

  • Pattern leakage: identifying repeated values (account flags, IPs, common headers) inside what is supposed to be opaque ciphertext.

  • Block substitution: cutting and pasting blocks between messages to alter the meaning of a ciphertext without knowing the key (e.g. swapping the "amount" block of one transaction into another).

  • Padding-oracle and chosen-plaintext attacks that ECB does not resist.

On Flutter, ECB shows up via AESMode.ecb in package:encrypt or ECBBlockCipher(AESEngine()) / registry strings like BlockCipher('AES/ECB/PKCS7') in package:pointycastle. Any sensitive data encrypted this way must be treated as compromised.

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

class EcbUsage {
  void pcDirect() {
    // VULNERABLE: Use of a broken or risky cryptographic mode of operation (ECB)
    final c1 = ECBBlockCipher(AESEngine());
    // VULNERABLE: Use of a broken or risky cryptographic mode of operation (ECB)
    final c2 = ECBBlockCipher(DESEngine());
    print('$c1 $c2');
  }
}

Remediation

Use an authenticated mode (AES-GCM, AES-CCM, ChaCha20-Poly1305) — these combine confidentiality with integrity in one primitive. If you must use an unauthenticated mode, pick AES-CBC or AES-CTR with a unique random IV per message and add a separate MAC.

// Vulnerable: ECB
final e = Encrypter(AES(key, mode: AESMode.ecb));
final c = ECBBlockCipher(AESEngine());

// Fixed: AES-GCM with a fresh random nonce per message
final cipher = AesGcm.with256bits();
final secretBox = await cipher.encrypt(
  plaintext,
  secretKey: key,
  nonce: cipher.newNonce(),
);

Configuration

This detector does not need any configuration.

References

© 2026 Xygeni. All rights reserved