Skip to main content
interlace
Plugin: node-securityRules

no-deprecated-cipher-method

Disallow deprecated crypto.createCipher/createDecipher methods

Detects usage of deprecated crypto.createCipher() and crypto.createDecipher() methods which don't use an IV. This rule is part of eslint-plugin-node-security and provides LLM-optimized error messages with fix suggestions.

🚨 Security rule | 💡 Provides suggestions | ⚠️ Set to error in recommended

Quick Summary

AspectDetails
CWE ReferenceCWE-327 (Broken Crypto)
SeverityHigh (security vulnerability)
Auto-Fix💡 Suggests createCipheriv/createDecipheriv
CategorySecurity
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForNode.js applications using crypto module

Vulnerability and Risk

Vulnerability: crypto.createCipher() and crypto.createDecipher() derive the encryption key from the password using MD5 (one iteration, no salt) and use no initialization vector (IV). This makes encryption deterministic and vulnerable.

Risk: Same password + same plaintext = same ciphertext. This enables pattern analysis, replay attacks, and makes brute-forcing passwords easier due to weak key derivation.

Rule Details

This rule detects calls to:

  • crypto.createCipher(algorithm, password)
  • crypto.createDecipher(algorithm, password)

Why This Matters

RiskImpactSolution
🔄 No IVDeterministic encryptionUse createCipheriv with random IV
🔑 Weak Key DerivationMD5 with no salt or iterationsUse scrypt or PBKDF2 for key derivation
⚠️ DeprecatedRemoved in future Node.js versionsMigrate now

Configuration

OptionTypeDefaultDescription
allowInTestsbooleanfalseAllow deprecated methods in test files
{
  rules: {
    'node-security/no-deprecated-cipher-method': ['error', {
      allowInTests: false
    }]
  }
}

Examples

❌ Incorrect

import crypto from 'crypto';

// Deprecated - no IV, weak key derivation
const cipher = crypto.createCipher('aes-256-cbc', password); // ❌
const encrypted = cipher.update(data, 'utf8', 'hex') + cipher.final('hex');

// Decryption also deprecated
const decipher = crypto.createDecipher('aes-256-cbc', password); // ❌
const decrypted =
  decipher.update(encrypted, 'hex', 'utf8') + decipher.final('utf8');

✅ Correct

import crypto from 'crypto';

// Proper key derivation using scrypt
const salt = crypto.randomBytes(16);
const key = crypto.scryptSync(password, salt, 32);

// Use createCipheriv with random IV
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); // ✅
const encrypted = Buffer.concat([
  salt, // Store salt for key derivation
  iv, // Store IV for decryption
  cipher.update(data),
  cipher.final(),
]);

// Decryption with proper IV
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); // ✅
const decrypted = Buffer.concat([
  decipher.update(encryptedData),
  decipher.final(),
]);

Proper Encryption Pattern

import crypto from 'crypto';

function encrypt(plaintext: string, password: string): Buffer {
  // Generate random salt and IV
  const salt = crypto.randomBytes(16);
  const iv = crypto.randomBytes(16);

  // Derive key using scrypt (memory-hard)
  const key = crypto.scryptSync(password, salt, 32);

  // Encrypt with GCM (authenticated encryption)
  const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
  const ciphertext = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final(),
  ]);
  const authTag = cipher.getAuthTag();

  // Return salt + iv + authTag + ciphertext
  return Buffer.concat([salt, iv, authTag, ciphertext]);
}

function decrypt(encrypted: Buffer, password: string): string {
  // Extract components
  const salt = encrypted.subarray(0, 16);
  const iv = encrypted.subarray(16, 32);
  const authTag = encrypted.subarray(32, 48);
  const ciphertext = encrypted.subarray(48);

  // Derive key
  const key = crypto.scryptSync(password, salt, 32);

  // Decrypt
  const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
  decipher.setAuthTag(authTag);

  return Buffer.concat([
    decipher.update(ciphertext),
    decipher.final(),
  ]).toString('utf8');
}

Security Impact

VulnerabilityCWEOWASPCVSSImpact
Broken Crypto327A02:20217.5 HighDeterministic encryption
Weak Key Derivation916A02:20215.9 MediumPassword brute-force

Migration Guide

Phase 1: Discovery

{
  rules: {
    'node-security/no-deprecated-cipher-method': 'warn'
  }
}

Phase 2: Replacement

// Replace deprecated methods
crypto.createCipher('aes-256-cbc', password); // ❌ Before
crypto.createCipheriv('aes-256-cbc', key, iv); // ✅ After

crypto.createDecipher('aes-256-cbc', password); // ❌ Before
crypto.createDecipheriv('aes-256-cbc', key, iv); // ✅ After

Phase 3: Enforcement

{
  rules: {
    'node-security/no-deprecated-cipher-method': 'error'
  }
}

Known False Negatives

Runtime-chosen method names

Why: A key computed at runtime resolves to no name to match.

// ❌ NOT DETECTED
const make = pickMethod();
const cipher = crypto[make]('aes-256-cbc', pwd);

Mitigation: Grep for both deprecated names — createCipher and createDecipher — and review every dynamic crypto[...] call, since the subscript above can resolve to either.

A STATIC subscript is detected — crypto['createCipher'](...) reports exactly as crypto.createCipher(...) does, and the suggestion re-quotes the replacement. This section previously claimed otherwise.

Further Reading

⚙️ Options

OptionTypeDefaultDescription
allowInTestsbooleanfalseAllow deprecated methods in test files

Use this rule

npm install -D oxlint-plugin-node-security
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-node-security"],  "rules": {    "node-security/no-deprecated-cipher-method": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-node-security'],    rules: {      'node-security/no-deprecated-cipher-method': 'error',    },  },});

oxlint-plugin-node-security re-exports eslint-plugin-node-security/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.