AES Cipher Mode Audit (PyCryptodome)

MEDIUM

Audit all AES.new() calls — verify the cipher mode is MODE_GCM, MODE_EAX, MODE_SIV, or MODE_CCM. Unauthenticated modes (MODE_ECB, MODE_CBC without HMAC) must not be used.

Rule Information

Language
Python
Category
Cryptography
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonpycryptodomecipher-modeunauthenticatedaesauditCWE-327OWASP-A02
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset python/PYTHON-CRYPTO-SEC-032 --project .
1
2
3
4
5
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

About This Rule

Understanding the vulnerability and how it is detected

Audit rule that flags all calls to `AES.new()` from PyCryptodome to prompt review of the cipher mode argument. This rule matches `PyCryptoAES.method("new")` without filtering on the mode constant because the analysis engine cannot currently distinguish `AES.MODE_GCM` from `AES.MODE_ECB` or `AES.MODE_CBC` when the mode is passed as a positional or keyword argument. This is a known engine limitation (the `not_in` qualifier for argument value exclusion is not yet available). PyCryptodome's AES.new() supports both secure and insecure modes in the same API: MODE_GCM, MODE_EAX, MODE_SIV, and MODE_CCM provide authenticated encryption (AEAD) and are safe for new code. MODE_ECB is deterministic and leaks plaintext patterns — it is a hard vulnerability (see SEC-030). MODE_CBC, MODE_CTR, MODE_CFB, and MODE_OFB provide confidentiality only and require a separate HMAC for integrity (see SEC-031). All AES.new() calls are flagged here as an audit checkpoint. Expected false positives include code using MODE_GCM or MODE_EAX correctly — verify the mode and suppress findings where authenticated modes are used. Findings using MODE_ECB or unauthenticated modes without HMAC are confirmed vulnerabilities.

How to Fix

Recommended remediation steps

  • 1Use AES.MODE_GCM with `encrypt_and_digest()` for all new PyCryptodome encryption — it provides confidentiality and authentication in a single call.
  • 2Use AES.MODE_EAX as an alternative to GCM — it has a simpler nonce handling model and is also authenticated.
  • 3Never use AES.MODE_ECB for any structured or multi-block data — replace it immediately with GCM or EAX.
  • 4If MODE_CBC must be used (protocol compatibility), pair it with an explicit HMAC-SHA256 over (iv || ciphertext) using a separate MAC key and verify before decrypting.
  • 5For migrating from MODE_CBC to GCM, note that GCM ciphertexts are longer by the tag length (16 bytes by default) — account for this in storage or wire format.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

OWASP Top 10
A02:2021 - Cryptographic Failures
PCI DSS v4.0
Requirement 4.2.1 -- use strong cryptography; authenticated modes required for cardholder data
NIST SP 800-131A
Mode selection guidance covered by SP 800-38 series; ECB not approved for general use
NIST SP 800-57
Key Management -- algorithm and mode selection for appropriate security level
NIST SP 800-53
SC-13: Cryptographic Protection -- use FIPS-approved algorithms and modes

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about AES Cipher Mode Audit (PyCryptodome)

This is an intentional audit-level rule. The engine matches all `AES.new()` calls because it cannot currently filter by the mode constant value. This means safe GCM calls are flagged alongside dangerous ECB calls. The intent is to ensure all AES usage is reviewed. For confirmed GCM, EAX, SIV, or CCM calls, suppress the finding with an inline annotation after verifying the usage is correct.
The engine currently lacks a `not_in` qualifier that would allow excluding specific argument values. Until that capability is available, this rule must audit all AES.new() calls. The known gap is documented in the ruleset roadmap. When the qualifier is implemented, this rule will be updated to flag only unauthenticated modes precisely.
Both GCM and EAX are authenticated encryption modes (AEAD) providing confidentiality and integrity. GCM is based on GHASH and is hardware-accelerated on modern CPUs (PCLMULQDQ instruction), making it faster in most environments. EAX is based on CMAC, is slightly simpler to implement correctly (no nonce length restrictions), and avoids potential multi-key GCM weaknesses. For most applications GCM is the practical choice due to hardware support; EAX is a good alternative when simplicity is preferred.
Yes, but only when paired with HMAC in Encrypt-then-MAC construction: encrypt first, then compute HMAC-SHA256 over (IV || ciphertext), store both. On decryption, verify the HMAC before any decryption call. The analysis engine cannot detect the HMAC pairing, so CBC usage will always be flagged by this rule. Consider migrating to GCM to eliminate the audit overhead.
SIV (Synthetic IV) is a nonce-misuse-resistant authenticated encryption mode. Unlike GCM, which produces completely broken output if a nonce is ever reused, SIV degrades gracefully under nonce reuse — it still provides integrity, only losing IND-CPA security for repeated messages. SIV is recommended when deterministic encryption is needed (e.g., encrypting database values where nonce storage is impractical) or when nonce generation cannot be guaranteed to be unique.
Replace `cipher = AES.new(key, AES.MODE_ECB)` with `cipher = AES.new(key, AES.MODE_GCM)`. Change `ciphertext = cipher.encrypt(data)` to `ciphertext, tag = cipher.encrypt_and_digest(data)`. Store the nonce (`cipher.nonce`) alongside the ciphertext and tag. For decryption, create a new cipher with the stored nonce and call `cipher.decrypt_and_verify(ciphertext, tag)` which raises `ValueError` if the tag is invalid. Note that existing ECB-encrypted data cannot be decrypted with GCM — you need to decrypt old data with ECB and re-encrypt with GCM.
No — this rule specifically targets `AES.new()`. DES and 3DES usage is covered by separate rules in the weak algorithm category. Both DES (56-bit) and 3DES (112-bit effective) are deprecated by NIST SP 800-131A and should be replaced with AES-256-GCM.

New feature

Get these findings posted directly on your GitHub pull requests

The AES Cipher Mode Audit (PyCryptodome) rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works