Skip to content

Local encryption

Varlock includes a built-in varlock() function that lets you secure local untracked secrets (typically in git-ignored env files like .env.local).

This allows you to keep everything out of plaintext - even temporary local overrides, or a “secret-zero” which is needed by some plugins to load the rest of your sensitive data.

Sensitive values will be stored encrypted, with the key linked to your local device, and requiring no extra configuration. The encryption mechanism varies per platform, but as it is tied to your device, these values are not meant to be shared or committed to git.

.env.local
PLAINTEXT=shh-im-secret # 🚨 danger
SECURED=varlock(local:abc123...) # ✅ secured at rest

You likely already have some plaintext secrets in a .env.local file. If not you can create one, and add some. Ensure those items are marked as @sensitive in your schema. Then you can use varlock encrypt to encrypt them in-place:

  1. Run varlock encrypt --file .env.local to encrypt them in-place
  2. Sensitive plaintext values are replaced with varlock("local:<***encrypted***>")
  3. Decryption happens automatically during varlock load / varlock run

Only plaintext values of @sensitive items are encrypted, so you may run it multiple times.

When you need to edit a value or add a new sensitive item, just set the value to varlock(prompt) and run varlock load. You will be prompted for the new value in a secure input prompt, and the encrypted value will be written back to the file automatically.

.env.local
EXISTING_ITEM=varlock(local:abc123...)
NEW_ITEM=varlock(prompt) # will prompt you for new value

You can also call the varlock encrypt CLI command to get a secure prompt to encrypt a single value. It will spit out an item you can copy/paste into your file:

$ varlock encrypt
◇ Enter the value you want to encrypt
│ ▪▪▪▪▪▪▪▪
Copy this into your .env.local file and rename the key appropriately:
SOME_SENSITIVE_KEY=varlock("local:ABC123...")

As outlined above, you can also run varlock encrypt --file .env.local to encrypt all sensitive plaintext values in a file in-place. This is a great way to quickly encrypt many secrets at once.

Use varlock encrypt to create encrypted payloads:

Terminal window
# Interactive: encrypt a single value
varlock encrypt
# Batch: encrypt all sensitive plaintext values in .env.local
varlock encrypt --file .env.local

Use varlock reveal to inspect decrypted values safely:

Terminal window
varlock reveal # interactive - select and reveal
varlock reveal API_KEY # securely reveal specific item
varlock reveal API_KEY --copy # copy to clipboard

Use varlock lock to invalidate biometric session cache when stepping away:

Terminal window
varlock lock

Varlock chooses the best available backend automatically:

PlatformBackendKey StorageBiometric
macOSSecure EnclaveHardware Secure EnclaveTouch ID
WindowsNCrypt TPM + Windows HelloTPM (when available), else DPAPIWindows Hello (face/fingerprint/PIN)
LinuxTPM2 / Secret ServiceTPM2 and/or system key storeYes (when configured via polkit/PAM)
All platformsFile-based fallback~/.varlock/ directoryNo

If native capabilities are unavailable, varlock falls back to file-based local encryption.

Verify encryption backend (macOS/Linux)

Terminal window
varlock-local-encrypt status

Verify encryption backend (Windows/WSL)

Terminal window
varlock-local-encrypt.exe status

Unattended decryption (headless servers & CI)

Section titled “Unattended decryption (headless servers & CI)”

Local encryption isn’t just for laptops. On a headless host with a TPM (a home server, a CI runner, a container host), varlock seals the key to the machine’s TPM and decrypts automatically at load with no prompt. That makes it a good way to store a “secret-zero” (like a 1Password service account token) that bootstraps the rest of your secrets:

.env.schema
# @type=opServiceAccountToken @sensitive @internal
OP_TOKEN=varlock("local:...")

On Linux this requires tpm2-tools and a TPM (see Linux setup below). The sealed value survives reboots and is bound to that specific machine. It can’t be copied to another host.

This unattended path applies to backends whose key is unsealed to the host: Linux (TPM2) and Windows (NCrypt/TPM). macOS is different: Secure Enclave keys never leave the enclave, and every decrypt requires user presence (Touch ID or password), so there is no unattended decrypt on macOS. A headless Mac or CI runner falls back to file-based encryption instead.

What this protects (and what it doesn’t)

Section titled “What this protects (and what it doesn’t)”

Hardware-backed encryption protects your secrets at rest: a stolen disk, a leaked backup, or an env file committed by mistake can’t be decrypted off the machine.

It does not protect against an attacker who is already running code as your user on that machine. They can ask the TPM to unseal the value exactly like varlock does. This is the same trade-off as tools like systemd-creds, and it’s inherent to unattended decryption: if no human is present to approve, anything running as you can decrypt.

If you want a presence gate (fingerprint / password / YubiKey via polkit + PAM) on every decrypt, register the policy:

Terminal window
sudo varlock-local-encrypt setup --linux-biometrics

Once configured, varlock’s normal decrypt flow requires user presence, so everyday loads are no longer unattended. Enable this only on interactive machines, not headless servers.

Treat this gate as a consent prompt, not an at-rest boundary. On Linux the TPM unseal isn’t bound to polkit, so (as noted above) other code already running as your user can still unseal directly. It means “a human approved this load,” not “only a human can ever decrypt.”

  • Native Swift helper (Secure Enclave integration)
  • Uses system-native secure input / auth prompts
  • Includes a menu bar applet flow for native interactions
  • Hardware-backed key protection via Secure Enclave with biometric auth where supported

✅ No additional install/setup steps required

  • Native helper with TPM-sealed key protection when a TPM 2.0 chip is available (via NCrypt / Platform Crypto Provider)
  • Falls back to DPAPI (user-session-scoped) when TPM sealing is unavailable
  • Windows Hello gates interactive decrypts (fingerprint/face/PIN), separate from at-rest protection, same as before
  • Windows native and WSL workflows are both supported (WSL uses the Windows varlock-local-encrypt.exe via --via-daemon; Hello + TPM behavior is identical)
  • Automated daemon startup/installation behavior is built in for biometric session flows
  • WSL decrypt flows use a native bridge to the Windows daemon path

✅ No additional install/setup steps required

New keys automatically use TPM sealing when available. Existing DPAPI keys are auto-upgraded to TPM sealing on the next successful decrypt (public key unchanged, no re-encryption of .env values). To upgrade without decrypting, use varlock-local-encrypt rewrap-key --key-id varlock-default.

varlock-local-encrypt.exe is Varlock’s official local-encryption helper (bundled with the npm package and standalone CLI). Windows Defender may flag it as Trojan:Win32/Wacatac.C!ml or similar, a common machine-learning false positive on new, unsigned executables. The binary is safe when obtained from official Varlock releases.

Verify the download: each GitHub release includes SHA256SUMS.txt with hashes for all native helpers. After installing, compare your file:

Terminal window
# PowerShell: run from the directory containing the .exe
Get-FileHash varlock-local-encrypt.exe -Algorithm SHA256

Match the hash against the native-bins/win32-x64/varlock-local-encrypt.exe line in SHA256SUMS.txt for your release version.

If quarantined: restore the file from Windows Security → Protection history, or add an exclusion for your project directory. Reinstall from npm or the official release if needed.

Permanent fix: official builds are moving to Authenticode code signing, which greatly reduces these alerts. Until your installed version is signed, verification via SHA256SUMS.txt is the recommended way to confirm authenticity.

  • Native Linux helper when available
  • User-presence verification via polkit/PAM (can support fingerprint/face/password depending system setup)

Common packages/tools:

  • tpm2-tools (plus distro TPM2 libs such as tpm2-tss)
  • polkit for user-presence authorization flows
  • xclip or xsel for varlock reveal --copy

Example installs:

Terminal window
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install -y tpm2-tools tpm2-tss policykit-1 xclip
Terminal window
# Fedora/RHEL variants
sudo dnf install -y tpm2-tools tpm2-tss polkit xclip

If biometric/user-presence prompts are unavailable on Linux, complete policy setup (native helper command):

Terminal window
sudo varlock-local-encrypt setup --linux-biometrics