Lines 1-38javascript
1import { readFileSync, existsSync } from "node:fs";
2import { execFileSync } from "node:child_process";
3import { relative } from "node:path";
4import { listFiles } from "../walk.js";
5const SERVER_ONLY_HINTS = [/\/api\//, /\/server\//, /route\.ts$/, /route\.js$/, /\.server\.ts$/, /middleware\.ts$/];
6function isLikelyServerFile(relPath) {
7 return SERVER_ONLY_HINTS.some((re) => re.test(relPath.replace(/\\/g, "/")));
9// Literal key prefixes for common providers — these are live-credential shaped strings,
10// not just env var *names*, so a match here is much higher-confidence than the generic scan.
11const LITERAL_KEY_PATTERNS = [
12 { name: "AWS access key", re: /AKIA[0-9A-Z]{16}/ },
13 { name: "Stripe live secret key", re: /sk_live_[0-9a-zA-Z]{16,}/ },
14 { name: "Stripe live restricted key", re: /rk_live_[0-9a-zA-Z]{16,}/ },
15 { name: "OpenAI API key", re: /sk-[a-zA-Z0-9]{20,}T3BlbkFJ[a-zA-Z0-9]{20,}|sk-proj-[a-zA-Z0-9_-]{20,}/ },
16 { name: "GitHub personal access token", re: /gh[pousr]_[A-Za-z0-9]{36,}/ },
17 { name: "Slack token", re: /xox[baprs]-[A-Za-z0-9-]{10,}/ },
18 { name: "Google/Firebase private key", re: /"private_key"\s*:\s*"-----BEGIN PRIVATE KEY-----/ },
CriticalCritical Secret
Package contains a critical-looking secret pattern.
dist/checks/secrets.jsView on unpkg · L18 CriticalSecret Pattern
RSA private key in dist/checks/secrets.js
dist/checks/secrets.jsView on unpkg · L18 19 { name: "SendGrid API key", re: /SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}/ },
20 { name: "Discord bot token", re: /[a-zA-Z0-9_-]{24}\.[a-zA-Z0-9_-]{6}\.[a-zA-Z0-9_-]{27}/ },
21 { name: "Database URL connection string", re: /postgres(?:ql)?:\/\/[^:]+:[^@]+@[^/]+/ },
23function gitTrackedFiles(root) {
25 const out = execFileSync("git", ["ls-files"], { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
26 return new Set(out.split("\n").map((f) => f.trim()).filter(Boolean));
29 return undefined; // not a git repo, or git unavailable — skip the tracked-file check
32export async function checkSecrets(stack) {
34 // .env files present but not gitignored
35 const envFiles = await listFiles(stack.root, [".env", ".env.local", ".env.production", ".env.development"]);
36 if (envFiles.length > 0) {
37 const gitignorePath = `${stack.root}/.gitignore`;
38 const gitignore = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf8") : "";