VNX-GO-036: Use of ECB block mode
Detects Go code that uses ECB mode: NewECBEncrypter/NewECBDecrypter, or a cipher.Block encrypting successive slices in a loop with no chaining.
| Field | Value |
|---|---|
| Rule ID | VNX-GO-036 |
| Severity | High |
| SARIF level | error |
| Kind | sast |
| Languages | Go |
| CWE | CWE-327 |
| CAPEC | CAPEC-32 |
| ATT&CK | T1068.003 |
| CWSS vector | CWSS:1.0/TI:H/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H |
| Tags | cryptography ecb block-mode weak-crypto |
| Source | internal/sast/rules/vnx-go-036.rego |
Overview
This rule flags Go code that implements ECB (Electronic Codebook) block cipher mode, typically identified by NewECBEncrypter, NewECBDecrypter, ECB, or manual block-at-a-time encryption using aes.NewCipher with block.BlockSize() loops that process each block independently with no IV or nonce chaining. ECB mode encrypts each plaintext block independently with the same key, which means identical plaintext blocks always produce identical ciphertext blocks. This makes ECB mode structurally unable to conceal data patterns regardless of the underlying cipher’s strength. This is mapped to CWE-327: Use of a Broken or Risky Cryptographic Algorithm.
Go’s standard library deliberately omits ECB mode from crypto/cipher, its absence is intentional. When developers implement ECB themselves or import a third-party package that exposes it, this rule raises a finding.
Why This Matters
The canonical demonstration of ECB’s weakness is the “ECB penguin”: encrypting the Tux Linux mascot image with ECB-AES produces output where the penguin’s outline remains clearly visible because regions of uniform colour map to uniform ciphertext blocks. The same structural leak occurs with any structured or partially-predictable plaintext, encrypted database records, JSON payloads, filesystem blocks, and network packets all contain repeated or predictable patterns that ECB makes visible.
In practice, an adversary with access to ECB-encrypted ciphertexts can perform chosen-plaintext attacks to recover plaintext by observing when ciphertext blocks repeat, use statistical analysis to fingerprint content even without decryption, and detect when two records share common prefix or suffix values, leaking business-sensitive relationships. These attacks require no knowledge of the key and succeed even against AES-256 in ECB mode, demonstrating that algorithm strength is irrelevant when the mode is fundamentally broken. CAPEC-32 (XSS via HTTP Request Headers) and broader cryptanalysis patterns both rely on this structural weakness.
What Gets Flagged
ECB through a library, or ECB written by hand:
// FLAGGED: crypt2go ecb package
mode := ecb.NewECBEncrypter(block)
// FLAGGED: each block encrypted independently in a loop
for i := 0; i < len(src); i += bs {
block.Encrypt(dst[i:i+bs], src[i:i+bs])
}
// FLAGGED: 3DES, same shape
for off := 0; off < len(p); off += c.BlockSize() {
c.Encrypt(out[off:], p[off:])
}
Not flagged: cipher.NewGCM, cipher.NewCBCEncrypter and the other crypto/cipher modes, hand-written CBC/CTR loops that XOR each block, a single-block Encrypt outside a loop (CMAC subkeys, key wrapping), ECB in identifiers, error messages, strings or comments, and test files.
Remediation
-
Replace ECB mode with AES-GCM. AES-GCM provides authenticated encryption (confidentiality and integrity), randomised ciphertext via a nonce, and is hardware-accelerated on all modern CPUs.
import ( "crypto/aes" "crypto/cipher" "crypto/rand" "io" ) // SAFE: AES-256-GCM, no pattern leakage, built-in integrity check func encrypt(key, plaintext, additionalData []byte) ([]byte, error) { block, err := aes.NewCipher(key) // key must be 16, 24, or 32 bytes if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } nonce := make([]byte, gcm.NonceSize()) if _, err = io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } // additionalData is authenticated but not encrypted (optional) return gcm.Seal(nonce, nonce, plaintext, additionalData), nil } -
Use AES-CTR when streaming encryption is required and you handle authentication separately with HMAC-SHA256. AES-CTR is not ECB: it XORs plaintext with a keystream derived from an incrementing counter and a nonce.
-
Consider
golang.org/x/crypto/chacha20poly1305for environments without AES hardware acceleration. ChaCha20-Poly1305 provides equivalent security with excellent software performance.
References
- CWE-327: Use of a Broken or Risky Cryptographic Algorithm
- OWASP Cryptographic Storage Cheat Sheet
- NIST SP 800-38A – Recommendation for Block Cipher Modes of Operation
- CAPEC-32: XSS via HTTP Request Headers
- Go crypto/cipher package documentation
- The ECB Penguin – Visual demonstration of ECB weakness
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-go-036
// nosec vnx-go-036
Or record an ignore rule: vulnetix ignore add --rule vnx-go-036 --reason "...". See Suppressing findings.