Sequelize Database Connection without TLS Enforcement

High Risk Insecure Communication
sequelizedatabasetlsencryptionnodejsorm

What it is

The Sequelize ORM configuration connects to databases without enforcing TLS encryption, potentially transmitting sensitive data over unencrypted connections. This vulnerability exposes database communications to eavesdropping and man-in-the-middle attacks.

// Vulnerable: Sequelize without TLS enforcement
const { Sequelize } = require('sequelize');

// Dangerous: No SSL/TLS configuration
const sequelize = new Sequelize('database', 'username', 'password', {
  host: 'db.example.com',
  port: 5432,
  dialect: 'postgres',
  // Missing SSL configuration
  logging: false
});

// Test connection without encryption
sequelize.authenticate()
  .then(() => console.log('Connected to database'))
  .catch(err => console.error('Connection failed:', err));
// Secure: Sequelize with TLS enforcement
const { Sequelize } = require('sequelize');
const fs = require('fs');

// Load SSL certificates if needed
const sslConfig = {
  require: true,
  rejectUnauthorized: true
};

// For custom CA certificates
if (process.env.DB_CA_CERT_PATH) {
  sslConfig.ca = fs.readFileSync(process.env.DB_CA_CERT_PATH);
}

// Secure: SSL/TLS enforced connection
const sequelize = new Sequelize(
  process.env.DB_NAME,
  process.env.DB_USER,
  process.env.DB_PASSWORD,
  {
    host: process.env.DB_HOST,
    port: process.env.DB_PORT || 5432,
    dialect: 'postgres',
    dialectOptions: {
      ssl: sslConfig
    },
    pool: {
      max: 10,
      min: 0,
      acquire: 30000,
      idle: 10000
    },
    logging: process.env.NODE_ENV === 'development' ? console.log : false
  }
);

// Test secure connection
sequelize.authenticate()
  .then(() => console.log('Securely connected to database'))
  .catch(err => console.error('Secure connection failed:', err));

💡 Why This Fix Works

The vulnerable code was updated to address the security issue.

Why it happens

Node.js applications using Sequelize ORM connect to databases without explicit SSL/TLS configuration. By default, Sequelize constructors like new Sequelize(database, username, password, { host, dialect }) do not enforce encrypted connections unless explicitly configured through dialectOptions.ssl. When developers initialize Sequelize with basic options containing only host, port, and dialect properties, the ORM establishes unencrypted TCP connections to database servers. All database queries, authentication credentials, and result sets containing sensitive data (user records, financial transactions, personal information) transmit in plaintext across network infrastructure. Attackers positioned on the network path between application servers and database servers can passively capture network traffic using tools like tcpdump or Wireshark to extract SQL queries revealing schema information, authentication tokens in WHERE clauses, and complete record sets in SELECT results.

Root causes

Missing SSL/TLS Configuration in Sequelize Options

Node.js applications using Sequelize ORM connect to databases without explicit SSL/TLS configuration. By default, Sequelize constructors like new Sequelize(database, username, password, { host, dialect }) do not enforce encrypted connections unless explicitly configured through dialectOptions.ssl. When developers initialize Sequelize with basic options containing only host, port, and dialect properties, the ORM establishes unencrypted TCP connections to database servers. All database queries, authentication credentials, and result sets containing sensitive data (user records, financial transactions, personal information) transmit in plaintext across network infrastructure. Attackers positioned on the network path between application servers and database servers can passively capture network traffic using tools like tcpdump or Wireshark to extract SQL queries revealing schema information, authentication tokens in WHERE clauses, and complete record sets in SELECT results.

Using Default Database Connection Settings Without Encryption

Development teams adopt default Sequelize configuration examples from documentation or tutorials that prioritize simplicity over security, omitting SSL/TLS settings entirely. Popular Sequelize getting-started guides often demonstrate basic connection patterns like sequelize = new Sequelize('database', 'user', 'password', { host: 'localhost', dialect: 'postgres' }) without including dialectOptions: { ssl: { require: true, rejectUnauthorized: true } }. These minimal configurations work correctly for local development environments where database and application run on the same machine or trusted network, but the same code gets deployed to production where application servers connect to managed database services (AWS RDS, Google Cloud SQL, Azure Database) over network infrastructure. Without explicit SSL enforcement, production database connections transmit cleartext traffic exposing credentials during authentication handshake and data during query execution. Database connection strings in environment variables containing passwords remain vulnerable during the initial connection establishment phase.

Disabling SSL Verification for Development that Carries to Production

Developers configure dialectOptions: { ssl: { rejectUnauthorized: false } } to bypass certificate validation errors when connecting to local development databases with self-signed certificates or invalid certificate chains. During local development, PostgreSQL or MySQL instances often use self-signed certificates that fail standard certificate validation, causing Sequelize connections to throw UNABLE_TO_VERIFY_LEAF_SIGNATURE or DEPTH_ZERO_SELF_SIGNED_CERT errors. Rather than properly configuring trusted CA certificates for development environments, developers set rejectUnauthorized: false to disable certificate validation entirely, allowing connections to proceed regardless of certificate validity. This configuration setting gets committed to version control in config/database.js or similar files, then deployed to production environments where it disables protection against man-in-the-middle attacks. Attackers can present fraudulent certificates to intercept encrypted database connections because the application accepts any certificate without validation, defeating the purpose of TLS encryption.

Improper Certificate Validation Configuration

Sequelize SSL configurations use incomplete security settings that establish encrypted connections without proper certificate validation. Developers configure dialectOptions: { ssl: true } using boolean shorthand instead of comprehensive SSL objects, or set ssl: { require: true } without including rejectUnauthorized: true to verify certificate chains. These partial configurations establish TLS-encrypted connections but skip critical validation steps: verifying the server's certificate is signed by a trusted Certificate Authority, checking the certificate hasn't expired, confirming the certificate's Common Name matches the database hostname, and validating the complete certificate chain to a trusted root CA. Without proper validation, applications are vulnerable to man-in-the-middle attacks where adversaries present self-signed certificates or certificates issued for different domains, intercepting and decrypting database traffic despite the TLS connection appearing secure. Missing CA certificate configuration (ssl.ca property) prevents validation against internal/private Certificate Authorities used in enterprise environments.

Missing dialectOptions for SSL Enforcement

Applications fail to include the dialectOptions property required for database-specific SSL configuration in Sequelize connection options. Different database dialects (postgres, mysql, mariadb, mssql, sqlite) implement SSL/TLS through database-specific connection libraries (pg for PostgreSQL, mysql2 for MySQL, tedious for MSSQL) that each require different SSL configuration structures passed through Sequelize's dialectOptions property. Developers configure top-level Sequelize options like host, port, database, username, password but omit the nested dialectOptions: { ssl: {...} } structure required to pass SSL settings to the underlying database driver. For PostgreSQL connections using the pg library, SSL settings must be provided as dialectOptions: { ssl: { require: true, rejectUnauthorized: true, ca, cert, key } }. MySQL connections require dialectOptions: { ssl: { require: true, rejectUnauthorized: true } } or dialectOptions: { ssl: 'Amazon RDS' } for AWS RDS certificate bundles. Without dialectOptions, SSL configuration provided at other levels in the options object gets ignored by the database driver, resulting in unencrypted connections.

Fixes

1

Enable SSL/TLS in Sequelize dialectOptions

Configure Sequelize to enforce encrypted database connections by adding dialectOptions.ssl to connection configuration: new Sequelize(database, username, password, { host, dialect: 'postgres', dialectOptions: { ssl: { require: true, rejectUnauthorized: true } } }). The require: true setting forces SSL/TLS connections and rejects unencrypted fallback attempts, while rejectUnauthorized: true enables certificate validation to verify the database server's identity. For PostgreSQL connections, ensure the pg library version supports SSL (pg@8.0.0 or later recommended). For MySQL/MariaDB using mysql2 driver, configure dialectOptions: { ssl: { require: true, rejectUnauthorized: true } }. For Microsoft SQL Server using tedious driver, use dialectOptions: { options: { encrypt: true, trustServerCertificate: false } }. Test SSL enforcement by attempting connections from application servers to verify encrypted connections are established and unencrypted connection attempts are rejected. Monitor database connection logs for SSL handshake completion messages confirming encrypted session establishment.

2

Configure Proper Certificate Validation

Implement complete certificate validation by setting rejectUnauthorized: true and providing trusted CA certificates in dialectOptions.ssl.ca property: dialectOptions: { ssl: { require: true, rejectUnauthorized: true, ca: fs.readFileSync('/path/to/ca-certificate.crt') } }. For AWS RDS databases, download the RDS CA certificate bundle from AWS and configure ca: fs.readFileSync('./rds-combined-ca-bundle.pem'). For Google Cloud SQL, download the server-ca.pem and configure ca: fs.readFileSync('./server-ca.pem'). For Azure Database services, download the BaltimoreCyberTrustRoot.crt.pem certificate. Never set rejectUnauthorized: false in production environments as this disables all certificate validation making TLS connections vulnerable to man-in-the-middle attacks. Validate certificate expiration dates and implement automated certificate rotation procedures before certificates expire. Configure certificate verification to check Subject Alternative Names (SAN) matching database hostnames to prevent certificate substitution attacks. Implement error handling for certificate validation failures using try/catch blocks around sequelize.authenticate() calls to detect and log SSL handshake errors.

3

Use Environment Variables to Manage SSL Settings

Externalize SSL configuration through environment variables to support different security requirements across development, staging, and production environments: const sslConfig = process.env.DB_SSL_ENABLED === 'true' ? { require: true, rejectUnauthorized: process.env.DB_SSL_REJECT_UNAUTHORIZED === 'true', ca: process.env.DB_SSL_CA_PATH ? fs.readFileSync(process.env.DB_SSL_CA_PATH) : undefined } : false. Define environment variables DB_SSL_ENABLED=true, DB_SSL_REJECT_UNAUTHORIZED=true, and DB_SSL_CA_PATH=/etc/ssl/certs/db-ca.pem for production deployments. For local development, set DB_SSL_ENABLED=false or provide development-specific CA certificates to avoid connection errors. Store environment variables in secure configuration management systems (AWS Secrets Manager, HashiCorp Vault, Kubernetes Secrets) rather than plaintext .env files. Document required SSL environment variables in deployment guides and validate their presence during application startup using configuration validation libraries. Implement separate configuration files for each environment (config/database.production.js, config/database.development.js) that read from environment variables, preventing hardcoded SSL settings from being committed to version control.

4

Implement Certificate Pinning for Enhanced Security

Add certificate pinning by validating specific certificate properties beyond standard CA chain validation: dialectOptions: { ssl: { require: true, rejectUnauthorized: true, ca: fs.readFileSync('/path/to/ca-cert.pem'), checkServerIdentity: (hostname, cert) => { const expectedFingerprint = process.env.DB_CERT_FINGERPRINT; const actualFingerprint = cert.fingerprint256; if (expectedFingerprint && actualFingerprint !== expectedFingerprint) { throw new Error('Certificate fingerprint mismatch'); } return undefined; } } }. Generate certificate fingerprints using: openssl x509 -in server-cert.pem -noout -fingerprint -sha256. Store expected fingerprints in environment variable DB_CERT_FINGERPRINT=SHA256:AA:BB:CC... Certificate pinning prevents acceptance of valid certificates issued by trusted CAs for different servers, defending against CA compromise scenarios. Implement certificate rotation procedures that update pinned fingerprints before certificates expire. For managed database services (RDS, Cloud SQL) where certificates are rotated automatically, pin intermediate CA certificates rather than leaf certificates. Monitor certificate validation errors in application logs to detect pinning failures during certificate rotation events. Document certificate pinning requirements in deployment runbooks including fingerprint update procedures.

5

Ensure All Database Connections Use Encryption

Audit all Sequelize instance creations across the codebase to verify consistent SSL configuration: grep -r "new Sequelize" to find all connection initializations and confirm each includes dialectOptions.ssl settings. Centralize database connection logic in a single configuration module (lib/database.js or config/sequelize.js) that enforces SSL for all connections: module.exports.createSequelize = (config) => { const baseOptions = { dialectOptions: { ssl: { require: true, rejectUnauthorized: true } } }; return new Sequelize(config.database, config.username, config.password, { ...config, ...baseOptions }); }. This pattern prevents inconsistent security configurations across multiple connection points. For applications with multiple database connections (primary database, read replicas, analytics databases), create a connection factory function that applies SSL configuration uniformly. Implement integration tests that verify SSL enforcement by attempting unencrypted connections which should fail with connection rejection errors. Use database client utilities like psql with sslmode=require parameter to verify database servers accept only encrypted connections. Configure database server firewall rules to reject plaintext connection attempts on port 5432/3306, forcing SSL-only connections.

6

Validate SSL Certificates Against Trusted CAs

Configure Sequelize SSL options to validate database certificates against system-trusted or explicitly provided Certificate Authorities: dialectOptions: { ssl: { require: true, rejectUnauthorized: true, ca: [fs.readFileSync('/etc/ssl/certs/ca-certificates.crt')], minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3' } }. The ca property accepts an array of CA certificate buffers, allowing validation against multiple trusted authorities for scenarios with certificate chains involving intermediate CAs. Set minVersion: 'TLSv1.2' to prevent fallback to deprecated SSL 3.0, TLS 1.0, or TLS 1.1 protocols with known vulnerabilities. Configure maxVersion: 'TLSv1.3' to use the latest TLS protocol supporting enhanced security features. For Ubuntu/Debian systems, system CA bundle is at /etc/ssl/certs/ca-certificates.crt; for RHEL/CentOS at /etc/pki/tls/certs/ca-bundle.crt; for macOS use security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain. Implement certificate verification error handling to distinguish between different failure types (expired certificate, untrusted CA, hostname mismatch) for operational debugging. Periodically update CA certificate bundles through system package managers (apt-get update ca-certificates, yum update ca-certificates) to maintain trust chain validity against revoked or expired CA certificates.

Detect This Vulnerability in Your Code

Sourcery automatically identifies sequelize database connection without tls enforcement and many other security issues in your codebase.