HIGH bleichenbacher attacknestjstypescript

Bleichenbacher Attack in Nestjs (Typescript)

Bleichenbacher Attack in Nestjs with Typescript

The Bleichenbacher attack exploits the padding validation mechanism in RSA OAEP operations, particularly when implementations leak information through timing or error responses. In Nestjs applications using the crypto module with Typescript types, improper error handling can expose padding validation status without revealing cryptographic secrets. This creates an oracle that allows attackers to decrypt TLS-encrypted traffic step by step.

When Nestjs services implement custom decryption wrappers using Typescript interfaces like interface DecryptResult { plaintext: string; iv: string; } and directly return HTTP 500 errors for padding failures, attackers can distinguish between valid padding and invalid ciphertext through response timing and status codes. This mirrors the original 1998 attack against PKCS#1 v1.5 but manifests differently in modern TypeScript-based Nestjs APIs.

Consider this vulnerable implementation in a Nestjs guard:

import { Injectable } from '@nestjs/common';
import * as crypto from 'crypto';

@Injectable()
export class RsaDecryptionGuard {
decrypt(encrypted: string): string {
const buffer = Buffer.from(encrypted, 'base64');
try {
const decipher = crypto.createDecipheriv('rsa-public-key', buffer);
return decipher.update(buffer.toString('utf8'), 'utf8', 'ascii');
} catch (error) {
// Vulnerable: Different error messages for padding vs other issues
if (error.message.includes('Padding')) {
return 'Invalid padding';
}
throw error;
}
}
}

This guard returns distinct error messages for padding failures versus other cryptographic errors. Attackers can automate requests against a Nestjs endpoint that uses this guard to encrypt chosen plaintexts and gradually recover ciphertext through adaptive queries. The Typescript type system doesn't prevent this side-channel leakage because the error handling logic exists outside type definitions.

Real-world impact includes extraction of session cookies, authentication tokens, and API keys from TLS-protected Nestjs microservices. This attack requires only unauthenticated access to the API endpoint and operates within the 5–15 second scan window of middleBrick's black-box testing.

Key exacerbating factors in Nestjs:

  • Default error handling in ExceptionFilter classes often preserves stack traces that reveal internal implementation details
  • Typescript interfaces don't enforce uniform error responses across modules
  • Nestjs middleware pipelines may log error types differently based on content length

middleBrick detects this pattern through its Authentication and Property Authorization checks by analyzing response variation across multiple crafted ciphertexts. The scan identifies inconsistent error messages and timing differences that indicate padding oracle vulnerabilities without requiring source code access.

Typescript-Specific Remediation in Nestjs

Mitigating Bleichenbacher-style padding oracle attacks in Nestjs requires uniform error responses and constant-time validation. The fix must be applied at the cryptographic layer while maintaining Typescript type safety.

First, replace distinct error messages with a single generic failure response. This Typescript interface defines consistent error handling:

interface DecryptResult {
success: boolean;
plaintext?: string;
error: string;
}

@Injectable()
export class SecureRsaDecryptionService {
async decrypt(encrypted: string): Promise {
const buffer = Buffer.from(encrypted, 'base64');
try {
const decipher = crypto.createDecipheriv('rsa-public-key', buffer);
const plaintext = decipher.update(buffer.toString('utf8'), 'utf8', 'ascii');
return { success: true, plaintext, error: '' };
} catch (error) {
// Constant-time handling: always return same structure
return { success: false, plaintext: '', error: 'Decryption failed' };
}
}
}

Second, implement constant-time comparison for padding checks using Typescript's crypto.timingSafeEqual:

import * as crypto from 'crypto';

function verifyPadding(ciphertext: Buffer): boolean {
const expectedPadding = Buffer.from('01', 'hex');
const actualPadding = ciphertext.slice(-2);
return crypto.timingSafeEqual(actualPadding, expectedPadding);
}

// Usage in service
if (!verifyPadding(fullCiphertext)) {
return { success: false, plaintext: '', error: 'Decryption failed' };
}

Third, configure Nestjs to globally handle errors uniformly:

app.useGlobalFilters(new HttpExceptionFilter());

Where HttpExceptionFilter ensures all exceptions return the same HTTP status code regardless of origin:

import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';

export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status = ctx.getRequest().httpVersion === '3' ? 400 : 500;
response.status(status).json({ error: 'Decryption failed' });
}
}

These changes eliminate the oracle effect by ensuring identical response behavior for all decryption failures. middleBrick's API Security Scan will detect the removal of padding-specific error messages through its Property Authorization and Input Validation checks, confirming that error responses no longer leak cryptographic implementation details.