Skip to content

Instantly share code, notes, and snippets.

@ustun
Created March 25, 2026 10:49
Show Gist options
  • Select an option

  • Save ustun/1f5a9974394cc32bba066e5584243ada to your computer and use it in GitHub Desktop.

Select an option

Save ustun/1f5a9974394cc32bba066e5584243ada to your computer and use it in GitHub Desktop.
Loading dotenvx encrypted local secrets with Decryption Key Stored in Keychain: https://dev.to/ustun/a-small-hardening-trick-for-envlocal-dotenvx-os-keychain-2533
import { execFileSync } from "node:child_process";
import { existsSync } from "node:fs";
import { resolve } from "node:path";
import { config } from "@dotenvx/dotenvx";
export function loadEnv(): void {
for (const file of [".env", ".env.local"]) {
const path = resolve(process.cwd(), file);
if (existsSync(path)) {
config({ path });
}
}
const localSecretsPath = resolve(process.cwd(), ".env.local.secrets");
if (!existsSync(localSecretsPath)) {
return;
}
if (process.env.USE_KEYCHAIN_FOR_DOTX === "true") {
try {
process.env.DOTENV_PRIVATE_KEY_LOCAL_SECRETS = execFileSync(
"security",
[
"find-generic-password",
"-a",
"LOCAL_SECRETS_DOTENVX_KEY",
"-s",
"LOCAL_SECRETS_DOTENVX_KEY",
"-w",
],
{ encoding: "utf-8" }
).trim();
} catch (err) {
throw new Error(
"Failed to read decryption key from macOS Keychain. " +
"Make sure the LOCAL_SECRETS_DOTENVX_KEY item exists. " +
"See scripts/store-keychain-key.sh for setup.",
{ cause: err }
);
}
}
config({ path: localSecretsPath, overload: true });
// The private key has done its job. Remove it from the environment so it
// is not visible in process.env dumps or child process inheritance.
delete process.env.DOTENV_PRIVATE_KEY_LOCAL_SECRETS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment