Api Key Exposure in Nestjs with Postgresql
Api Key Exposure in Nestjs with Postgresql — how this specific combination creates or exposes the vulnerability
In a NestJS application that uses Postgresql as the data store, API key exposure often occurs through a misconfiguration or insecure usage pattern that spans the framework, the database driver, and runtime environment. A common scenario involves storing database credentials or service-specific API keys in environment variables and accessing them in NestJS via ConfigService. If developers accidentally log these values, include them in error responses, or expose them through an unguarded endpoint, the keys can be leaked to unauthorized clients.
When using TypeORM with Postgresql in NestJS, the connection configuration typically resides in a configuration file (e.g., config.ts or a database module). If the configuration object containing sensitive credentials is serialized into logs, error traces, or HTTP responses—such as when an exception handler exposes the full configuration object—API keys embedded in the Postgresql connection string or related service clients can be exposed. For example, a connection URI like postgresql://user:[email protected]:5432/appdb directly embeds the key; if this string is mishandled, the key is compromised.
Another vector specific to the NestJS + Postgresql combination arises from dynamic configuration or migrations that inject keys into runtime queries or repository methods. If API keys are used to authorize specific database operations (for example, row-level security tokens passed as query parameters), and those keys are included in logs, console outputs, or GraphQL responses without sanitization, they can be harvested by attackers. MiddleBrick’s checks for Data Exposure and Unsafe Consumption are designed to detect such leakage by analyzing runtime responses and spec-defined schemas for sensitive patterns like hardcoded keys or credentials in output fields.
SSRF (Server-Side Request Forgery) can also amplify exposure: a vulnerable endpoint in NestJS that accepts URLs may be coerced into making requests to internal metadata services or database dashboards where Postgresql instances expose configuration or diagnostic endpoints containing API keys. Since middleBrick tests for SSRF and Data Exposure in parallel, it can identify whether an API inadvertently reflects or leaks database-related credentials through HTTP responses or error messages.
Additionally, if the NestJS application exposes an OpenAPI specification that includes examples or schemas containing API key values for Postgresql service integrations, those keys can be exposed to anyone who retrieves the spec. middleBrick’s OpenAPI/Swagger analysis resolves all $ref definitions and cross-references spec definitions with runtime findings to detect such risky documentation practices, ensuring that no credential appears in generated schemas or sample payloads.
Postgresql-Specific Remediation in Nestjs — concrete code fixes
To remediate API key exposure in NestJS with Postgresql, apply strict separation of configuration from code and enforce output sanitization. Store database credentials in a secure secrets manager or environment variables, and never embed keys directly in connection strings that may be serialized. Use NestJS’s ConfigModule to inject sanitized values while ensuring sensitive fields are omitted from logs and responses.
Secure Configuration Example
Use encrypted environment variables and a validated configuration module to avoid accidental exposure:
// config/database.config.ts
import { DataSourceOptions } from 'typeorm';
export const databaseConfig: DataSourceOptions = {
type: 'postgres',
host: process.env.PGHOST || 'localhost',
port: Number(process.env.PGPORT) || 5432,
username: process.env.PGUSER,
password: process.env.PGPASSWORD, // key stored as env var, not in code
database: process.envPGDATABASE,
ssl: {
rejectUnauthorized: process.env.PGSSL_REJECT_UNAUTHORIZED === 'true',
},
};
Ensure that password values are never logged or stringified. Implement a custom logger that filters sensitive fields:
// logger.filter.ts
import { Logger } from '@nestjs/common';
export class SafeLogger {
private readonly logger = new Logger(SafeLogger.name);
log(message: any, ...optionalParams: any[]) {
const filtered = this.filterSecrets(message);
this.logger.log(filtered, ...optionalParams);
}
private filterSecrets(obj: any): any {
if (obj && typeof obj === 'object' && obj.password) {
return { ...obj, password: '***filtered***' };
}
return obj;
}
}
Postgresql Query Handling
When using TypeORM repositories, avoid passing raw API keys as query parameters. Instead, use parameterized queries and ensure that sensitive fields are omitted from responses:
// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
username: string;
@Column({ select: false }) // prevents automatic inclusion in SELECT
apiKey: string; // sensitive field, not returned by default
}
If you must return key-related metadata, explicitly sanitize the output in a DTO:
// user.dto.ts
export class UserDto {
id: number;
username: string;
// apiKey is intentionally omitted
}
Connection and Migration Security
During migrations, avoid printing connection URIs. Use environment-based configuration and ensure that migration scripts do not log credentials:
// src/migrations/12345678901234-initial.ts
import { MigrationInterface, QueryRunner } from 'typeorm';
export class InitialMigration implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise {
await queryRunner.query(`CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, username VARCHAR(255))`);
// Do not log connection strings or keys here
}
}
By combining secure configuration, output filtering, and disciplined query practices, the NestJS + Postgresql stack can avoid API key exposure while maintaining operational integrity. middleBrick’s checks for Data Exposure, Unsafe Consumption, and LLM/AI Security help validate that no sensitive values appear in runtime outputs or specifications.