Secretlint CLI for Secret Detection
Secretlint is a powerful CLI tool designed for scanning codebases to detect and prevent the leakage of sensitive data like API keys, credentials, and private information. The current stable version is 12.2.0, with minor and patch releases occurring frequently, and major versions introducing breaking changes like Node.js engine requirements. It offers a highly extensible architecture through pluggable rules and presets (e.g., `@secretlint/secretlint-rule-preset-recommend`), supporting various file formats and offering multiple output formatters including `stylish`, `mask-result`, and `github` annotations. Key differentiators include its focus on precise secret detection, a flexible configuration system using `.secretlintrc` files, and the ability to mask secrets in output, making it suitable for CI/CD pipelines and pre-commit hooks.
Common errors
-
Error: Node.js v18.17.1 is not supported. secretlint requires Node.js v22.0.0 or later.
cause Running secretlint with an unsupported Node.js version.fixUpgrade your Node.js environment to version 22 or higher using `nvm install 22 && nvm use 22` or similar version management tools. -
zsh: no matches found: "**/*"
cause The shell attempted to expand the glob pattern before passing it to secretlint, and found no matches, or interpreted it incorrectly.fixEnsure glob patterns are enclosed in double quotes when used in the terminal: `secretlint "**/*"`. -
Failed to load config file: .secretlintrc.json. Error: Failed to parse JSON file
cause The `.secretlintrc.json` file is either missing, has incorrect JSON syntax, or is not accessible.fixRun `npx secretlint --init` to create a default configuration, or carefully check your `.secretlintrc.json` file for syntax errors. -
ReferenceError: SecretlintCoreResult is not defined
cause Attempting to use a type or function from the `secretlint` package programmatically without a proper ES module import statement.fixEnsure you are using `import { SecretlintCoreResult } from 'secretlint';` for TypeScript or CommonJS equivalent when using programmatically.
Warnings
- breaking Secretlint v12.0.1 and later require Node.js version 22 or higher. Earlier Node.js versions are not supported and will cause runtime errors.
- breaking Starting with Secretlint v12.0.0, new rules were added to the default `@secretlint/secretlint-rule-preset-recommend`. This means existing projects updating to v12 might suddenly report new secrets or issues that were not previously detected.
- gotcha When using glob patterns in shell commands (e.g., `bash`, `zsh`), you must wrap the patterns in double quotes (e.g., `secretlint "**/*"`). Failure to do so will cause your shell to expand the glob, potentially leading to errors like 'no matches found' or incorrect file processing.
- gotcha The `--output` option fundamentally alters `secretlint`'s exit status. If `--output` is specified, `secretlint` will exit with status `0` (success) even if secrets are found. This can hide issues in CI/CD pipelines.
- gotcha Secret detection inherently comes with a risk of false positives. Generic patterns can flag legitimate, non-secret data. Relying solely on default presets without review can lead to unnecessary alerts.
Install
-
npm install secretlint -
yarn add secretlint -
pnpm add secretlint
Imports
- run
const run = require('secretlint').run;import { run } from 'secretlint'; - SecretlintCoreResult
import { SecretlintCoreResult } from 'secretlint'; - loadConfig
import { loadConfig } from 'secretlint'; - SecretlintCLIOptions
import { SecretlintCLIOptions } from 'secretlint';
Quickstart
import { run } from 'secretlint';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
const tempDir = path.join(process.cwd(), '.secretlint-temp');
const tempFile = path.join(tempDir, 'example.js');
const configFile = path.join(tempDir, '.secretlintrc.json');
async function quickstart() {
await fs.mkdir(tempDir, { recursive: true });
await fs.writeFile(tempFile, 'const secretKey = "sk_live_YOUR_SECRET_KEY_123";');
await fs.writeFile(configFile, JSON.stringify({
"rules": [
{
"id": "@secretlint/secretlint-rule-preset-recommend",
"rule": "@secretlint/secretlint-rule-preset-recommend"
}
]
}, null, 2));
try {
console.log('Running secretlint CLI via npx:');
// Using child_process for CLI demo, or `run` for programmatic
const { execa } = await import('execa'); // Using dynamic import for execa
const cliResult = await execa('npx', [
'secretlint',
tempFile,
'--secretlintrc', configFile,
'--format=stylish'
], { reject: false, cwd: tempDir });
console.log(cliResult.stdout);
if (cliResult.exitCode === 1) {
console.log('CLI detected secrets and exited with code 1.');
} else {
console.log('CLI finished, no secrets detected or --output was used.');
}
console.log('\nRunning secretlint programmatically with `run` function:');
const programmaticResult = await run([tempFile], {
cwd: tempDir,
secretlintrc: configFile,
format: 'mask-result'
});
console.log(programmaticResult.output);
if (programmaticResult.ok === false) {
console.log('Programmatic run detected secrets.');
} else {
console.log('Programmatic run finished, no secrets detected.');
}
} catch (error) {
console.error('An error occurred:', error);
} finally {
await fs.rm(tempDir, { recursive: true, force: true });
}
}
quickstart();