Files
Charon/docs/security/api-key-handling.md
GitHub Actions 3169b05156 fix: skip incomplete system log viewer tests
- Marked 12 tests as skip pending feature implementation
- Features tracked in GitHub issue #686 (system log viewer feature completion)
- Tests cover sorting by timestamp/level/method/URI/status, pagination controls, filtering by text/level, download functionality
- Unblocks Phase 2 at 91.7% pass rate to proceed to Phase 3 security enforcement validation
- TODO comments in code reference GitHub #686 for feature completion tracking
- Tests skipped: Pagination (3), Search/Filter (2), Download (2), Sorting (1), Log Display (4)
2026-02-09 21:55:55 +00:00

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:

  1. Empty keys: Returns [empty]
  2. Short keys (< 16 chars): Returns [REDACTED]
  3. 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

  1. Use secure file permissions (0600) for key files
  2. Store keys in environment variables for production deployments
  3. Never commit keys to version control (.gitignore all key files)
  4. Encrypt keys at rest when possible
  5. 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

  1. Rotate keys regularly (every 90 days recommended)
  2. Rotate immediately after:
    • Suspected compromise
    • Employee offboarding
    • Log exposure incidents
    • Security audit findings
  3. Use graceful rotation:
    • Generate new key
    • Update configuration
    • Test with new key
    • Revoke old key

Rotation Procedure

  1. Generate new bouncer in CrowdSec:

    cscli bouncers add new-bouncer-name
    
  2. 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
    
  3. Restart Charon to apply new key

  4. Revoke old bouncer:

    cscli bouncers delete old-bouncer-name
    

Incident Response

If Keys Are Exposed

If API keys are accidentally logged or exposed:

  1. Rotate the key immediately (see rotation procedure above)
  2. Purge logs containing the exposed key:
    • Local log files
    • Log aggregation services (CloudWatch, Splunk, etc.)
    • Backup archives
  3. Audit access logs for unauthorized usage
  4. Update incident response procedures to prevent recurrence
  5. 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

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)