Skip to main content
interlace
Plugin: pgRules

no-insecure-ssl

Prevents disabling SSL certificate validation in PostgreSQL connections.

CWE: CWE-693

⚠️ This rule errors by default in the recommended config.

Quick Summary

AspectDetails
CWE ReferenceCWE-295 (Improper Certificate Validation)
SeverityHigh (CVSS: 7.5)
CategorySecurity

Rule Details

Setting rejectUnauthorized: false disables SSL certificate verification, making connections vulnerable to man-in-the-middle attacks.

❌ Incorrect

const client = new Client({
  ssl: {
    rejectUnauthorized: false, // Dangerous!
  },
});

const pool = new Pool({
  ssl: {
    rejectUnauthorized: false,
  },
});

✅ Correct

// Default (secure)
const client = new Client({ ssl: true });

// With CA certificate
const client = new Client({
  ssl: {
    ca: fs.readFileSync('/path/to/server-ca.pem').toString(),
  },
});

// Explicit secure setting
const client = new Client({
  ssl: {
    rejectUnauthorized: true,
  },
});

Error Message Format

🔒 CWE-295 | Insecure SSL: rejectUnauthorized: false disables certificate validation | HIGH
   Fix: Remove rejectUnauthorized: false or set to true, and provide CA certificate

When Not To Use It

  • In development environments with self-signed certificates (use environment variables instead)
  • Never disable in production

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Also checked (since 2026-10)

  • Every branch of a conditional ssl value — ssl: isProd ? { rejectUnauthorized: false } : false, the widely copied Heroku snippet, disables verification in exactly the environment that matters.
  • postgres.js postgres(url, { ssl }) and pg-promise pgp({ ssl }).
  • A config returned from a function in the same file, and a config object declared with pg's PoolConfig / ClientConfig type (or satisfies it).

Configuration Object from a package or path alias

Why: A config imported from a RELATIVE module or JSON file is read (import dbConfig from './database.json' is reported when it sets rejectUnauthorized: false). One from an npm package or a path alias is not.

// ❌ NOT DETECTED - config from a path alias
import dbConfig from '@/config/database';
const client = new Client(dbConfig);

Spread Operator

Why: Spread objects hide their properties at lint time.

// ❌ NOT DETECTED - rejectUnauthorized in spread
const baseConfig = getDbConfig();
const client = new Client({ ...baseConfig }); // May include insecure SSL

Mitigation: Explicitly set SSL options. Validate config at runtime.

Use this rule

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

oxlint-plugin-postgresql-security re-exports eslint-plugin-postgresql-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.