Security fixes are applied to the latest code on main.
Older branches and unpublished snapshots are handled on a best-effort basis.
If you discover a security issue in this repository:
- Do not open a public GitHub issue.
- Use GitHub's private vulnerability reporting flow for this repository if it is enabled.
- If private reporting is unavailable, contact the maintainers directly before any public disclosure.
Please include:
- a clear description of the issue
- affected paths or components
- reproduction steps or a proof of concept
- the likely impact
- any mitigation ideas you already have
- Acknowledgment within 2 business days
- Initial triage within 7 days
- Coordinated disclosure after a fix or mitigation is available
This policy covers:
- shared Python packages and launchers
- build, release, and CI automation
- repository tooling that ships to or supports downstream repos
This section addresses minimizing secret-keyword exposure and preventing hardcoded secrets in the repository.
NEVER commit to the repository:
- API keys (OpenAI, Google, AWS, GitHub, Stripe, etc.)
- Database credentials or connection strings with passwords
- Private encryption keys or SSH keys
- OAuth tokens or bearer tokens
- AWS/Azure/GCP service account credentials
- Any other sensitive credentials or secrets
Load all secrets at runtime from environment variables:
import os
api_key = os.getenv('GEMINI_API_KEY')
if not api_key:
raise ValueError("GEMINI_API_KEY environment variable not set")With python-dotenv for local development:
from dotenv import load_dotenv
import os
load_dotenv() # Loads from .env (excluded from version control)
api_key = os.getenv('API_KEY')For each component requiring secrets, maintain a .env.example showing the expected structure:
# .env.example - DO NOT include real values
GEMINI_API_KEY=your_key_here
GITHUB_TOKEN=your_token_here
DATABASE_URL=postgresql://user:password@localhost/dbnameExamples in this repo:
.env.example— Flask/calculator app secretssrc/document_processing/pdf_renamer/.env.example— Gemini API key
For GUI applications that persist user credentials, use python-keyring to store in OS-native secure storage:
import keyring
# Save to OS keyring
keyring.set_password("app_name", "username", secret_value)
# Retrieve from OS keyring
secret_value = keyring.get_password("app_name", "username")Example: src/document_processing/pdf_renamer/config.py demonstrates this pattern.
The .gitignore excludes:
.env*files (all environment variable files)*.key,*.pem(certificates and keys)secrets/directoriesconfig/secrets/directories- Cloud provider credential files
When adding new config files containing secrets, update .gitignore.
Use the built-in secrets scanner:
python3 -m src.python.src.utils.secrets_scanner src/This detects patterns matching:
- AWS keys:
AKIAprefix - GitHub tokens:
ghp_prefix - OpenAI keys:
sk-prefix - Slack tokens:
xox*prefix - Private keys:
-----BEGIN PRIVATE KEY-----
During code review, verify:
- String literals: No hardcoded API keys, passwords, or tokens
- Docstrings & Examples: No real credentials in documentation
- Test Fixtures: Use placeholder values only
- Logging: Never log secrets
- Exceptions: Don't expose secrets in error messages
PDF Renamer (src/document_processing/pdf_renamer/):
- Demonstrates priority-ordered secret retrieval: environment → OS keyring → none
- Uses interactive setup to store credentials securely
- See
config.pyfor the pattern
Folder Packer Pro (src/folder_packer_pro/):
- User-provided passwords (never hardcoded)
- Uses PBKDF2 + AES-256 for encryption
- Passwords stay in memory only during operations
- Notify the team immediately via email (not a public issue)
- Revoke the credential (regenerate API keys, rotate passwords)
- Remove from history with team approval (force-push if needed)
- Monitor for abuse of the exposed credential