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(),
);
References
-
OWASP Top 10 2025 - A04 : Cryptographic Failures.
-
Block cipher mode — ECB (Wikipedia) — The "ECB penguin" illustration and block-pattern leakage details
-
OWASP Cryptographic Storage Cheat Sheet — Mode-of-operation selection guidance
-
package:encrypt (pub.dev) — Prefer
AESMode.gcm/AESMode.cbcwith a secure-random IV overAESMode.ecb -
package:cryptography (pub.dev) —
AesGcm.with256bits()is the recommended authenticated cipher constructor