Why AI tools produce this: AI coding tools generate this anti-pattern by default, it appears in a large share of AI-written auth code.
Why this matters
Setting rejectUnauthorized: false or NODE_TLS_REJECT_UNAUTHORIZED=0 makes the connection accept ANY certificate, including self-signed or attacker-supplied ones. This removes the protection TLS provides against man-in-the-middle attacks: anyone able to intercept the network path can present a forged certificate, then read and modify the traffic (credentials, tokens, data).
Keep certificate validation enabled. If the server uses a private or self-signed CA, supply that CA explicitly instead of turning validation off, e.g. new https.Agent({ ca: fs.readFileSync('ca.pem') }). See CWE-295 and the Node.js TLS docs.
VULNERABLE
vulnerable.ts
import axios from 'axios';import https from 'node:https';import tls from 'node:tls';declare const url: string;// A custom HTTPS agent that accepts any certificate — classic MITM hole.// ruleid: auth.tls.reject-unauthorizedconst insecureAgent = new https.Agent({ rejectUnauthorized: false });// axios call wiring up the same insecure agent inline.// ruleid: auth.tls.reject-unauthorizedconst res = axios.get(url, { httpsAgent: new https.Agent({ rejectUnauthorized: false }),});// Raw https.request options with validation disabled.// ruleid: auth.tls.reject-unauthorizedconst req = https.request({ hostname: 'api.example.com', port: 443, rejectUnauthorized: false,});// tls.connect with validation disabled.// ruleid: auth.tls.reject-unauthorizedconst socket = tls.connect({ host: 'api.example.com', port: 443, rejectUnauthorized: false });// The global escape hatch that disables validation process-wide.// ruleid: auth.tls.reject-unauthorizedprocess.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';export { insecureAgent, res, req, socket };
SAFE
safe.ts
import axios from 'axios';import fs from 'node:fs';import https from 'node:https';declare const url: string;// ok: auth.tls.reject-unauthorized -- validation explicitly kept onconst strictAgent = new https.Agent({ rejectUnauthorized: true });// ok: auth.tls.reject-unauthorized -- plain request, default validation appliesconst res = https.get(url);// ok: auth.tls.reject-unauthorized -- pins a private CA instead of disabling checksconst pinnedAgent = new https.Agent({ ca: fs.readFileSync('ca.pem') });// ok: auth.tls.reject-unauthorized -- axios call with no insecure optionsconst data = axios.get(url, { timeout: 5000 });export { strictAgent, res, pinnedAgent, data };
Suppressing this rule
If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.