Critical security fix addressing CWE-312/315/359 (Cleartext Storage/Cookie Storage/Privacy Exposure) where CrowdSec bouncer API keys were logged in cleartext. Implemented maskAPIKey() utility to show only first 4 and last 4 characters, protecting sensitive credentials in production logs. Enhanced CrowdSec configuration import validation with: - Zip bomb protection via 100x compression ratio limit - Format validation rejecting zip archives (only tar.gz allowed) - CrowdSec-specific YAML structure validation - Rollback mechanism on validation failures UX improvement: moved CrowdSec API key display from Security Dashboard to CrowdSec Config page for better logical organization. Comprehensive E2E test coverage: - Created 10 test scenarios including valid import, missing files, invalid YAML, zip bombs, wrong formats, and corrupted archives - 87/108 E2E tests passing (81% pass rate, 0 regressions) Security validation: - CodeQL: 0 CWE-312/315/359 findings (vulnerability fully resolved) - Docker Image: 7 HIGH base image CVEs documented (non-blocking, Debian upstream) - Pre-commit hooks: 13/13 passing (fixed 23 total linting issues) Backend coverage: 82.2% (+1.1%) Frontend coverage: 84.19% (+0.3%)
6.9 KiB
API Key Security Guidelines
Overview
This document outlines security best practices for handling API keys and other sensitive credentials in Charon. These guidelines help prevent common vulnerabilities like CWE-312 (Cleartext Storage of Sensitive Information), CWE-315 (Cleartext Storage in Cookie), and CWE-359 (Exposure of Private Personal Information).
Logging Best Practices
NEVER Log Sensitive Credentials
Critical Rule: Never log sensitive credentials (API keys, tokens, passwords) in plaintext.
Masking Implementation
Charon implements secure API key masking that shows only the first 4 and last 4 characters:
// ✅ GOOD: Masked key
logger.Infof("API Key: %s", maskAPIKey(apiKey))
// Output: "API Key: abcd...xyz9"
// ❌ BAD: Full key exposure
logger.Infof("API Key: %s", apiKey)
// Output: "API Key: abcd1234567890xyz9" (SECURITY RISK!)
Masking Rules
The maskAPIKey() function implements these rules:
- Empty keys: Returns
[empty] - Short keys (< 16 chars): Returns
[REDACTED] - Normal keys (≥ 16 chars): Shows first 4 + last 4 characters (e.g.,
abcd...xyz9)
These rules ensure that:
- Keys cannot be reconstructed from logs
- Users can still identify which key was used (by prefix/suffix)
- Debugging remains possible without exposing secrets
Key Storage
File Storage Requirements
API keys must be stored with secure file permissions:
// Save with restricted permissions (owner read/write only)
err := os.WriteFile(keyFile, []byte(apiKey), 0600)
Required permissions: 0600 (rw-------)
- Owner: read + write
- Group: no access
- Others: no access
Storage Best Practices
- Use secure file permissions (0600) for key files
- Store keys in environment variables for production deployments
- Never commit keys to version control (.gitignore all key files)
- Encrypt keys at rest when possible
- Use separate keys per environment (dev/staging/prod)
Key Validation
Format Validation
The validateAPIKeyFormat() function enforces these rules:
- Length: 16-128 characters
- Charset: Alphanumeric + underscore (
_) + hyphen (-) - No spaces or special characters
// Valid keys
"api_key_1234567890123456" // ✅
"api-key-ABCDEF1234567890" // ✅
"1234567890123456" // ✅
// Invalid keys
"short" // ❌ Too short (< 16 chars)
strings.Repeat("a", 129) // ❌ Too long (> 128 chars)
"api key with spaces" // ❌ Invalid characters
"api@key#special" // ❌ Invalid characters
Validation Benefits
- Prevents weak/malformed keys
- Detects potential key corruption
- Provides early failure feedback
- Improves security posture
Security Warnings
Log Aggregation Risks
If logs are shipped to external services (CloudWatch, Splunk, Datadog, etc.):
- Masked keys are safe to log
- Full keys would be exposed across multiple systems
- Log retention policies apply to all destinations
Error Message Safety
Never include sensitive data in error messages:
// ✅ GOOD: Generic error
return fmt.Errorf("authentication failed")
// ❌ BAD: Leaks key info
return fmt.Errorf("invalid API key: %s", apiKey)
HTTP Response Safety
Never return API keys in HTTP responses:
// ✅ GOOD: Omit sensitive fields
c.JSON(200, gin.H{
"status": "registered",
"keyFile": "/path/to/key", // Path only, not content
})
// ❌ BAD: Exposes key
c.JSON(200, gin.H{
"apiKey": apiKey, // SECURITY RISK!
})
Key Rotation
Rotation Best Practices
- Rotate keys regularly (every 90 days recommended)
- Rotate immediately after:
- Suspected compromise
- Employee offboarding
- Log exposure incidents
- Security audit findings
- Use graceful rotation:
- Generate new key
- Update configuration
- Test with new key
- Revoke old key
Rotation Procedure
-
Generate new bouncer in CrowdSec:
cscli bouncers add new-bouncer-name -
Update Charon configuration:
# Update environment variable CHARON_SECURITY_CROWDSEC_API_KEY=new-key-here # Or update key file echo "new-key-here" > /path/to/bouncer.key chmod 0600 /path/to/bouncer.key -
Restart Charon to apply new key
-
Revoke old bouncer:
cscli bouncers delete old-bouncer-name
Incident Response
If Keys Are Exposed
If API keys are accidentally logged or exposed:
- Rotate the key immediately (see rotation procedure above)
- Purge logs containing the exposed key:
- Local log files
- Log aggregation services (CloudWatch, Splunk, etc.)
- Backup archives
- Audit access logs for unauthorized usage
- Update incident response procedures to prevent recurrence
- Notify security team following your organization's procedures
Log Audit Procedure
To check if keys were exposed in logs:
# Search local logs (should find NO matches)
grep -r "full-api-key-pattern" /var/log/charon/
# Expected: No results (keys should be masked)
# If matches found, keys were exposed - follow incident response
Compliance
Standards Addressed
This implementation addresses:
- CWE-312: Cleartext Storage of Sensitive Information
- CWE-315: Cleartext Storage in Cookie
- CWE-359: Exposure of Private Personal Information
- OWASP A02:2021: Cryptographic Failures
Compliance Frameworks
Key handling practices align with:
- GDPR: Personal data protection (Article 32)
- PCI-DSS: Requirement 3.4 (Render PAN unreadable)
- SOC 2: Security criteria (CC6.1 - Logical access controls)
- ISO 27001: A.9.4.3 (Password management)
Testing
Security Test Coverage
All API key handling functions have comprehensive unit tests:
# Run security tests
go test ./backend/internal/api/handlers -run TestMaskAPIKey -v
go test ./backend/internal/api/handlers -run TestValidateAPIKeyFormat -v
go test ./backend/internal/api/handlers -run TestSaveKeyToFile_SecurePermissions -v
Test Scenarios
Tests cover:
- ✅ Empty keys →
[empty] - ✅ Short keys (< 16) →
[REDACTED] - ✅ Normal keys →
abcd...xyz9 - ✅ Length validation (16-128 chars)
- ✅ Character set validation
- ✅ File permissions (0600)
- ✅ No full key exposure in logs
References
- OWASP Logging Cheat Sheet
- CWE-312: Cleartext Storage
- CWE-315: Cookie Storage
- CWE-359: Privacy Exposure
- NIST SP 800-63B: Digital Identity Guidelines
Updates
| Date | Change | Author |
|---|---|---|
| 2026-02-03 | Initial documentation for Sprint 0 security fix | GitHub Copilot |
Last Updated: 2026-02-03 Next Review: 2026-05-03 (Quarterly)