no-hardcoded-credentials
Prevents hardcoded passwords and connection strings in PostgreSQL client initialization.
CWE: CWE-522
⚠️ This rule errors by default in the recommended config.
Quick Summary
| Aspect | Details |
|---|---|
| CWE Reference | CWE-798 (Hardcoded Credentials) |
| Severity | High (CVSS: 7.5) |
| Category | Security |
Rule Details
Hardcoded credentials in source code can be exposed through version control, logs, or error messages.
❌ Incorrect
// Hardcoded password
const client = new Client({
password: 'supersecret123',
});
// Hardcoded connection string
const pool = new Pool('postgres://user:password@localhost/db');✅ Correct
// Environment variables
const client = new Client({
password: process.env.PG_PASSWORD,
});
// Connection string from environment
const pool = new Pool(process.env.DATABASE_URL);
// Config file (not committed to VCS)
const config = require('./config.local.json');
const client = new Client(config.database);Error Message Format
The rule provides LLM-optimized error messages (Compact 2-line format) with actionable security guidance:
🔒 CWE-798 OWASP:A04 CVSS:9.8 | Hardcoded Credentials detected | CRITICAL [SOC2,PCI-DSS,HIPAA,GDPR,ISO27001,NIST-CSF]
Fix: Review and apply the recommended fix | https://owasp.org/Top10/A04_2021/Message Components
| Component | Purpose | Example |
|---|---|---|
| Risk Standards | Security benchmarks | CWE-798 OWASP:A04 CVSS:9.8 |
| Issue Description | Specific vulnerability | Hardcoded Credentials detected |
| Severity & Compliance | Impact assessment | CRITICAL [SOC2,PCI-DSS,HIPAA,GDPR,ISO27001,NIST-CSF] |
| Fix Instruction | Actionable remediation | Follow the remediation steps below |
| Technical Truth | Official reference | OWASP Top 10 |
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Template Literals with Credentials
Why: The rule only checks Literal nodes, not template literals.
// ❌ NOT DETECTED
const client = new Client({
password: `supersecret123`, // Template literal, not string literal
});Configs from packages or path aliases
Why: Configs and config factories in the same file, in RELATIVE modules
(./config), and in relative JSON files (./database.json) are read. One from
an npm package or a path alias (@/config) is not.
// ❌ NOT DETECTED
import { getConfig } from '@/config';
const client = new Client(getConfig());Also checked (since 2026-10)
- A
postgres://user:password@hostDSN anywhere in the file, not only in a constructor — the config module that holds it is the usual place. Loopback hosts (localhost,127.0.0.1,[::1]) are skipped. - postgres.js
postgres(url | options)and pg-promisepgp(options).
Spread Operator
Why: The rule iterates over properties, not spread sources.
// ❌ NOT DETECTED
const secrets = { password: 'hardcoded' };
const client = new Client({ ...secrets });Variable References
Why: Values stored in variables aren't traced to their literal origin.
// ❌ NOT DETECTED
const password = 'supersecret123';
const client = new Client({ password });Workaround: Use secret scanning tools (e.g., gitleaks, truffleHog) in CI/CD.
TypeORM Configs Belong to typeorm-security
A postgres URL inside a TypeORM options object — new DataSource({ type: 'postgres', url }), TypeOrmModule.forRoot({ … }), an ormconfig export — is
not reported here. It is
typeorm-security/no-hardcoded-credentials's
finding, so a project running both plugins gets one report per secret, not two.
The object counts as TypeORM's when it has a postgres-family type
(postgres, aurora-postgres, cockroachdb) and the file imports typeorm /
@nestjs/typeorm or the object carries TypeORM keys (entities,
synchronize, migrations, subscribers, migrationsRun). Enable
typeorm-security to keep coverage for those configs.
When Not To Use It
- In test files with fixture data
- In documentation examples
Related Rules
- no-insecure-ssl (planned) - Prevents insecure SSL settings
Use this rule
npm install -D oxlint-plugin-postgresql-security{ "jsPlugins": ["oxlint-plugin-postgresql-security"], "rules": { "postgresql-security/no-hardcoded-credentials": "error" }}import { defineConfig } from 'vite-plus';export default defineConfig({ lint: { jsPlugins: ['oxlint-plugin-postgresql-security'], rules: { 'postgresql-security/no-hardcoded-credentials': '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.