
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
cross-keychain
Advanced tools
Cross-platform secret storage for Node.js applications and CLI usage.
npm install cross-keychain
# or
yarn add cross-keychain
# or
pnpm add cross-keychain
Once installed, you can use the cross-keychain command to manage secrets:
# Store a secret (will prompt for password)
cross-keychain set myapp username
# Password for 'username' in 'myapp': [hidden input]
# Password stored
# Store a secret via stdin (non-interactive)
echo "my-secret" | cross-keychain set myapp username
# Password stored
# Retrieve a password
cross-keychain get myapp username
# my-secret
# Retrieve credentials as JSON
cross-keychain get myapp username --mode creds --output json
# {"username":"username","password":"my-secret"}
# Retrieve any credential for a service
cross-keychain get myapp --mode creds
# username
# my-secret
# Delete a secret
cross-keychain del myapp username
# Password deleted
# List available backends
cross-keychain --list-backends
# file (priority: 1) File backend
# keychain (priority: 10) macOS Keychain
# Force a specific backend
cross-keychain get myapp username --backend file
# Disable keyring (use null backend)
cross-keychain --disable
# Null backend configured
# Diagnose current configuration
cross-keychain diagnose
# {
# "backend": "keychain",
# "available_backends": [...]
# }
Operations:
get - Retrieve a password or credentialset - Store a password (prompts securely or reads from stdin)del - Delete a passworddiagnose - Print environment detailsOptions:
--backend <id> - Force a specific backend--mode <mode> - Mode for 'get' operation (password or creds)--output <format> - Output format for 'get' operation (plain or json)--password-stdin - Read password from stdin for 'set' operation--list-backends - List detected backends--disable - Persistently configure the null backendimport {
setPassword,
getPassword,
deletePassword,
getCredential,
} from "cross-keychain";
// Store a secret
await setPassword("myapp", "username", "john_doe");
// Retrieve a secret
const password = await getPassword("myapp", "username");
console.log(password); // "john_doe"
// Delete a secret
await deletePassword("myapp", "username");
// Get credential for a service and account
const credential = await getCredential("myapp", "username");
console.log(credential); // { username: "username", password: "john_doe" }
// Get first available credential for a service
const firstCredential = await getCredential("myapp");
console.log(firstCredential); // { username: "username", password: "john_doe" }
setPassword(service, account, password)service (string): The service name to store the password underaccount (string): The account namepassword (string): The password to storeStores a password in the system keyring.
getPassword(service, account)service (string): The service nameaccount (string): The account nameReturns the stored password for the given service and account, or null if not found.
deletePassword(service, account)service (string): The service nameaccount (string): The account nameDeletes the stored password for the given service and account.
getCredential(service, account?)service (string): The service nameaccount (string, optional): The account name. If not provided, returns the first available credential for the serviceReturns a credential object with username and password properties for the given service and account, or null if not found.
Platform Limitations:
Note: If multiple credentials exist for the service, the one returned is not guaranteed to be the same every time.
Keyring supports various configuration methods to customize backend selection and behavior.
TS_KEYRING_BACKEND - Forces a specific backend to be used:
# Force native macOS Keychain (Security.framework bindings - when available)
export TS_KEYRING_BACKEND=native-macos
# Force CLI-based macOS Keychain (security command - when available)
export TS_KEYRING_BACKEND=macos
# Force Windows Credential Manager (when available)
export TS_KEYRING_BACKEND=windows
# Force Linux Secret Service (when available)
export TS_KEYRING_BACKEND=secret-service
# Force the file backend
export TS_KEYRING_BACKEND=file
# Force the null backend (disables storage)
export TS_KEYRING_BACKEND=null
KEYRING_PROPERTY_* - Override backend-specific properties:
# File backend: Custom storage location
export KEYRING_PROPERTY_FILE_PATH="/custom/path/secrets.json"
# macOS backend: Use specific keychain
export KEYRING_PROPERTY_KEYCHAIN="/path/to/custom.keychain"
# Linux Secret Service: Custom application identifier
export KEYRING_PROPERTY_APPLICATION="my-custom-app"
export KEYRING_PROPERTY_APPID="my-custom-app" # Alternative name
# Linux Secret Service: Use specific collection
export KEYRING_PROPERTY_COLLECTION="my-collection"
export KEYRING_PROPERTY_PREFERRED_COLLECTION="my-collection" # Alternative name
# Windows: Set credential persistence level
export KEYRING_PROPERTY_PERSIST="local" # or "session", "enterprise"
Keyring uses a JSON configuration file for persistent settings:
Location: keyring.config.json in the platform-specific config directory:
%LOCALAPPDATA%\Keyring\keyring.config.json or %APPDATA%\Keyring\keyring.config.json~/.config/keyring/keyring.config.json (or $XDG_CONFIG_HOME/keyring/keyring.config.json)~/.config/keyring/keyring.config.json (or $XDG_CONFIG_HOME/keyring/keyring.config.json)Schema:
{
"defaultBackend": "file",
"backendProperties": {
"file": {
"file_path": "/custom/path/secrets.json"
},
"native-macos": {
"keychain": "/path/to/custom.keychain"
},
"macos": {
"keychain": "/path/to/custom.keychain"
},
"secret-service": {
"application": "my-app",
"collection": "my-collection"
},
"windows": {
"persist": "local"
}
}
}
Example configurations:
// Disable keyring (use null backend)
{
"defaultBackend": "null"
}
// Use file backend with custom location
{
"defaultBackend": "file",
"backendProperties": {
"file": {
"file_path": "/secure/vault/secrets.json"
}
}
}
// Use Windows Credential Manager with session persistence
{
"defaultBackend": "windows",
"backendProperties": {
"windows": {
"persist": "session"
}
}
}
file_path (string): Custom path for the secrets JSON file
{dataRoot}/secrets.json"/custom/path/secrets.json"key_file_path (string): Custom path for the encryption key file
{configRoot}/file.key"/custom/path/file.key"KEYRING_FILE_MASTER_KEY - 64 hex character (32 byte) key to override file-based keykeychain (string): Path to a specific keychain file
"/path/to/custom.keychain"keychain (string): Path to a specific keychain file
"/path/to/custom.keychain"application / appid (string): Application identifier for stored secrets
"ts-keyring""my-application"collection / preferred_collection (string): Specific keyring collection to use
"my-collection"persist (string | number): Credential persistence level
"session" / 1: Credentials are deleted when the user logs off"local" / 2: Credentials persist until explicitly deleted (default)"enterprise" / 3: Credentials roam with the user profileThe disable() function creates a configuration file that forces the null backend:
import { disable } from "cross-keychain";
// Persistently disable keyring
await disable();
Behavior:
keyring.config.json with "defaultBackend": "null"KeyringError if configuration file already exists0600 (owner read/write only)To re-enable keyring: Delete the configuration file manually
Keyring uses the following priority order for backend selection:
TS_KEYRING_BACKEND (highest priority)defaultBackend settingEnvironment property overrides (KEYRING_PROPERTY_*) always take precedence over configuration file settings.
cross-keychain uses a priority-based system to automatically select the best available backend:
| Backend | Platform | Priority | Method | Security |
|---|---|---|---|---|
| Native macOS Keychain | macOS | 10 | Security.framework bindings | ✅ Highest - Direct API access |
| Native Windows Credential Manager | Windows | 10 | Native DPAPI bindings | ✅ Highest - Direct API access |
| Native Linux Secret Service | Linux | 10 | Native DBus bindings | ✅ Highest - Direct API access |
| macOS Keychain (CLI Fallback) | macOS | 5 | security command | ✅ High - OS keychain, password in process list |
| Windows Credential Manager (Fallback) | Windows | 5 | PowerShell DPAPI | ✅ High - OS credential manager |
| Linux Secret Service (Fallback) | Linux | 4.8 | secret-tool | ✅ High - OS keyring service |
| File Backend | All | 0.5 | Encrypted JSON file | ⚠️ Limited - AES-256-GCM encrypted, file-based |
| Null Backend | All | -1 | No storage | ❌ None - Disabled |
The native backends (macOS, Windows, and Linux) use @napi-rs/keyring (installed as an optional dependency) for direct API access through native bindings, providing the highest security and performance. These backends eliminate password exposure in process lists and shell command injection risks that can occur with CLI-based approaches. If the native module is not available, the library automatically falls back to shell-based backends.
⚠️ CRITICAL SECURITY WARNING ⚠️
The security of your stored credentials depends entirely on which backend is used. Always use native OS backends in production environments.
These backends use your operating system's built-in credential management and provide strong security:
🔒 macOS Keychain (Native)
🔒 macOS Keychain (CLI - Fallback)
security command-line tool🔒 Windows Credential Manager
🔒 Linux Secret Service
WARNING: The file backend provides encryption but has significant limitations compared to OS backends.
Security features:
~/.config/keyring/file.key (0600 permissions)KEYRING_FILE_MASTER_KEY env var for key management0600 (owner read/write only)0700 (owner access only)Threat model - Protects against:
Security limitations:
Key management:
~/.config/keyring/file.key (auto-generated if missing)KEYRING_FILE_MASTER_KEY env var (64 hex chars = 32 bytes)Acceptable use cases:
Secure password input:
cross-keychain set service username (interactive prompt - secure)cross-keychain set service username --password-stdin < file (reads from stdin)echo "password" | cross-keychain set service username (may appear in process lists)Production recommendations:
Credentials and configuration files are stored in platform-specific directories:
Windows:
%LOCALAPPDATA%\Keyring or %APPDATA%\KeyringmacOS:
~/.local/share/keyring (or $XDG_DATA_HOME/keyring)~/.config/keyring (or $XDG_CONFIG_HOME/keyring)Linux:
~/.local/share/keyring (or $XDG_DATA_HOME/keyring)~/.config/keyring (or $XDG_CONFIG_HOME/keyring)This project uses modern development tools and practices. Here are the key npm scripts for contributors:
npm run test – Run the complete Vitest test suite with coverage reportingnpm run test:watch – Run tests in watch mode for active developmentnpm run lint – Lint source code with ESLint to enforce code quality standardsnpm run lint:fix – Automatically fix linting issues where possiblenpm run build – Build the project using tsup (TypeScript bundler)npm run typecheck – Run TypeScript compiler for type checking without emitting filesnpm run coverage – Generate detailed test coverage reportsnpm run format – Format code using Prettiernpm run format:check – Check code formatting without making changesnpm run ci – Run the complete CI pipeline locally (lint + typecheck + test + build)npm run security – Run npm audit to check for security vulnerabilitiesnpm run deps:check – Check for outdated dependenciesnpm run deps:unused – Find unused dependencies with knipClone and install dependencies:
git clone https://github.com/magarcia/cross-keychain.git
cd cross-keychain
npm install
Run the development workflow:
npm run test:watch # Start tests in watch mode
npm run lint # Check code quality
npm run typecheck # Verify TypeScript types
Before committing:
npm run ci # Run full CI pipeline locally
The project uses Husky for Git hooks to automatically run linting and tests before commits.
Contributions and bug reports are welcome! Read the CONTRIBUTING.md guide and adhere to the CODE_OF_CONDUCT.md when participating. Issues and pull requests live at the GitHub repository.
Released under the MIT License.
FAQs
Cross-platform secret storage
The npm package cross-keychain receives a total of 569 weekly downloads. As such, cross-keychain popularity was classified as not popular.
We found that cross-keychain demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.