How to Securely Manage Sensitive Credentials in PicList-Core Configurations
Use environment variables via .env files for secrets, leverage built-in CLI masking, and isolate credentials per uploader while keeping configuration files out of version control.
PicList-Core handles image uploads across multiple cloud platforms, requiring secure storage of API tokens, secret keys, and passwords. Understanding how to securely manage sensitive credentials in PicList-Core configurations is essential for protecting your cloud storage accounts and maintaining operational security. The codebase implements specific safeguards in src/utils/configManager.ts and src/utils/runScripts.ts that you can leverage alongside operational best practices.
Environment-Based Secret Injection
The most secure way to handle credentials is to keep them out of the configuration JSON entirely. PicList-Core supports this through automatic .env file loading.
In src/utils/runScripts.ts, the getFreshEnv function reads a .env file at runtime and merges its variables into process.env:
// src/utils/runScripts.ts (excerpt)
import dotenv from 'dotenv';
function getFreshEnv(envPath: string): Record<string, string> {
if (fs.existsSync(envPath)) {
const buf = fs.readFileSync(envPath);
const config = dotenv.parse(buf);
// Merge into process.env – makes credentials available to uploaders
for (const k in config) process.env[k] = config[k];
return config;
}
return {};
}
Best practice: Create a .env file in your project root (ensure it is git-ignored) containing your secrets:
GITHUB_TOKEN=ghp_XXXXXXXXXXXXXXXXXXXX
SMMS_TOKEN=your_smms_token
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...
Launch PicList-Core using cross-env or allow runScripts.ts to load the .env automatically. The uploader modules will read these values from process.env without ever persisting them to disk in the JSON configuration.
CLI Masking and Display Protection
When viewing configurations via the command line, PicList-Core automatically masks sensitive fields to prevent accidental exposure.
In src/plugins/commander/configManager.ts, the config-show command implements logic that detects credential-related keys:
// src/plugins/commander/configManager.ts (excerpt)
const displayValue =
typeof value === 'string' &&
(key.includes('password') ||
key.includes('token') ||
key.includes('key'))
? '***' // secret hidden
: JSON.stringify(value);
ctx.log.info(` ${key}: ${displayValue}`);
Best practice: Always use the official CLI commands (picgo config-show, piclist config-show) rather than manually cat-ing the configuration file. If you need to debug, avoid console.log statements that print the entire config object; instead, log specific non-sensitive fields.
Per-Uploader Credential Isolation
PicList-Core enforces separation of concerns by defining distinct TypeScript interfaces for each uploader's credentials in src/types/index.ts.
Each uploader has its own configuration structure:
IGithubConfigcontainstoken,repo,branchISmmsConfigcontainstokenIAwsS3PListUserConfigcontainsaccessKeyID,secretAccessKey,sessionToken
This isolation ensures that credentials for one service cannot accidentally leak into another uploader's configuration object.
Best practice: When adding new uploaders or modifying existing ones, maintain this namespace isolation. Rotate credentials for one uploader without affecting others, and use the specific config interfaces to validate that only expected fields are present.
Multi-Config Rotation and Management
PicList-Core supports multiple configuration profiles per uploader, allowing you to rotate credentials without downtime.
In src/utils/configManager.ts, the syncConfigToPicBed method handles the migration between the legacy single-config format and the new multi-config structure (uploader.{name}.configList):
// src/utils/configManager.ts (excerpt)
syncConfigToPicBed() {
// When a config becomes the default, it syncs to legacy picBed location
// but remains isolated in the configList array
}
Best practice: Use the config-use command to switch between credential sets rather than editing JSON manually. When a token expires or is compromised, add a new configuration entry with fresh credentials using config-add (or the equivalent API), then activate it with config-use <uploader> <config-name>. This leaves the old credential in place (for rollback if needed) while immediately switching to the secure replacement.
Plugin Security Boundaries
Third-party plugins operate within a restricted context that prevents unauthorized modification of your credentials.
The IPicGo interface in src/types/index.ts exposes ctx.getConfig<T>() as read-only for general plugin use. Write access is restricted to ctx.saveConfig(), which validates against the internal schema:
// src/types/index.ts (excerpt)
interface IPicGo {
getConfig<T>(name?: string): T | undefined;
// saveConfig is the only write path, enforcing schema validation
}
Best practice: Audit third-party plugins before installation. Verify that they only use ctx.getConfig() to read necessary settings and do not attempt to manipulate the configuration object directly. Prefer plugins from the official PicList-Core ecosystem that have been reviewed for security compliance.
File System Permissions and Version Control
Operational security extends beyond the codebase to how you store configuration files on disk.
Best practice:
- Git-ignore your config: Never commit
config.jsonor.envfiles to version control. Add them to.gitignoreimmediately. - Restrict file permissions: Set your configuration directory to
chmod 700and the config file tochmod 600(read/write for owner only) on Unix systems. - Use OS-specific vaults: On macOS, consider storing secrets in Keychain and referencing them via environment variables. On Windows, use Credential Manager or Windows Environment Variables.
- Separate concerns: Keep PicList-Core's configuration in
$HOME/.picgo(the default) rather than project directories to avoid accidental exposure in shared codebases.
Summary
- Use
.envfiles loaded bysrc/utils/runScripts.tsto inject secrets intoprocess.envwithout writing them to JSON configuration files. - Rely on built-in masking in
src/plugins/commander/configManager.tsto prevent credential exposure in CLI output. - Isolate credentials per uploader using the typed interfaces in
src/types/index.tsto prevent cross-contamination. - Rotate credentials safely using the multi-config support in
src/utils/configManager.tsrather than manual JSON editing. - Restrict plugin access by auditing third-party code that uses
ctx.getConfig()and ensuring write operations only occur throughctx.saveConfig(). - Protect files on disk with strict permissions (600/700) and git-ignore rules to prevent accidental version control commits.
Frequently Asked Questions
How do I prevent my API tokens from appearing in the PicList-Core configuration file?
Store your secrets in a .env file in your project root. The runScripts.ts utility automatically parses this file and merges values into process.env at runtime, allowing uploaders to read tokens from environment variables rather than the JSON configuration. Ensure .env is listed in .gitignore and set file permissions to 600 to restrict access.
Can I switch between multiple sets of credentials for the same uploader without editing the config file manually?
Yes. PicList-Core supports multi-configuration profiles per uploader through the configList structure managed in src/utils/configManager.ts. Use the config-use <uploader> <config-name> command to activate a specific credential set. This updates the active configuration without requiring manual JSON edits and allows instant rollback to previous credentials if needed.
Are third-party plugins able to read or steal my stored credentials?
Plugins receive a read-only context (ctx) that exposes getConfig() but restricts write access to the saveConfig() API, which validates against the internal schema. While plugins can theoretically read configuration values, they cannot modify the config file directly. Always audit third-party plugin code before installation to ensure it only accesses necessary configuration keys and does not transmit data externally.
What fields are automatically masked when displaying configuration via the CLI?
The config-show command in src/plugins/commander/configManager.ts automatically masks values for any key containing the substrings password, token, or key, replacing the actual value with ***. This prevents accidental exposure of credentials in terminal output, logs, or screenshots. Always use official CLI commands rather than cat or text editors to inspect active configurations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →