# Changelog All notable changes to Charon will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Security - **CRITICAL**: Fixed CVE-2025-68156 by upgrading expr-lang/expr to v1.17.7 - **Component**: expr-lang/expr (used by CrowdSec for expression evaluation in scenarios and parsers) - **Vulnerability**: Regular Expression Denial of Service (ReDoS) - **Severity**: HIGH (CVSS score: 7.5) - **Impact**: Malicious regular expressions in CrowdSec configurations could cause CPU exhaustion - **Resolution Date**: January 11, 2026 - **Verification Methods**: - Binary inspection: `go version -m ./cscli` confirms v1.17.7 in production artifacts - Trivy scan: 0 HIGH/CRITICAL vulnerabilities in Charon application code - Source build: Custom Dockerfile builds CrowdSec from patched source - **Test Coverage**: Backend 86.2%, Frontend 85.64% (all tests passing) - **Status**: ✅ Patched and verified in production build - See [CrowdSec Source Build Documentation](docs/plans/crowdsec_source_build.md) for technical details ### Added - **Pre-commit hook for fast Go linters (staticcheck, govet, errcheck, ineffassign, unused)** - New config file: `backend/.golangci-fast.yml` (lightweight for pre-commit) - VS Code tasks: "Lint: Staticcheck (Fast)" and "Lint: Staticcheck Only" - Makefile targets: `lint-fast` and `lint-staticcheck-only` - Comprehensive troubleshooting guide for staticcheck failures in copilot-instructions.md - **golangci-lint installation instructions** in CONTRIBUTING.md - Implementation summary: docs/implementation/STATICCHECK_BLOCKING_INTEGRATION_COMPLETE.md ### Changed - **BREAKING:** Commits are now BLOCKED if staticcheck or other fast linters find issues - Pre-commit hooks now run golangci-lint with essential linters (~11s runtime) - Test files (`_test.go`) excluded from staticcheck (matches CI behavior) - Emergency bypass available with `git commit --no-verify` (use sparingly) ### Fixed - **CI**: Fixed Docker image artifact save failing with "reference does not exist" error in PR builds - Root cause: Manual image tag reconstruction did not match actual tag applied by docker/build-push-action - Solution: Use exact tag from docker/metadata-action output instead of reconstructing - Impact: PR builds now successfully save image artifacts for supply chain verification - Downstream fix: Enables verify-supply-chain-pr job to run correctly on all PRs - **Docs-to-Issues Workflow**: Resolved issue where PR status checks didn't appear when workflow ran (PR #461) - Removed `[skip ci]` flag from workflow commit message to enable CI validation on PRs - Maintained infinite loop protection via path filters (`!docs/issues/created/**`) and bot guard - All CI checks now run properly on PRs created by automated issue processing - Zero security risks, comprehensive validation completed - See [Docs-to-Issues Fix Implementation Summary](docs/implementation/DOCS_TO_ISSUES_FIX_2026-01-11.md) - **CI Workflow Documentation**: Resolved GitHub Advanced Security false positive warnings and clarified supply chain verification behavior (PR #461) - Documented workflow migration from `docker-publish.yml` to `docker-build.yml` (Dec 21, 2025) - Added explanatory comments to all security scanning workflows - Fixed `supply-chain-verify.yml` to trigger on ALL branches (removed GitHub Actions branch filter limitation) - Updated SECURITY.md with comprehensive scanning coverage documentation - All security scanning verified as active with zero gaps - See [CI Workflow Fixes Implementation Summary](docs/implementation/CI_WORKFLOW_FIXES_2026-01-11.md) ### Added - **Supply Chain Security**: Comprehensive supply chain security implementation with cryptographic verification (PR #XXX) - **Cosign Signatures**: All container images cryptographically signed with keyless Sigstore Cosign - **SLSA Provenance**: SLSA Level 3 compliant build provenance attestation for verifiable builds - **SBOM Generation**: Software Bill of Materials in SPDX format for all releases - **Transparency Log**: All signatures recorded in public Rekor transparency log - **VS Code Integration**: Three new agent skills for developers: - `security-verify-sbom`: Verify SBOM contents and check for vulnerabilities - `security-sign-cosign`: Sign container images with Cosign - `security-slsa-provenance`: Generate SLSA provenance attestation - **Automated Verification**: Tasks integrated into development workflow - **Documentation**: Complete user and developer guides for verification and usage - See [Supply Chain Security User Guide](docs/guides/supply-chain-security-user-guide.md) for verification instructions - See [Supply Chain Security Developer Guide](docs/guides/supply-chain-security-developer-guide.md) for development workflow ### Verified - **React 19 Compatibility:** Confirmed React 19.2.3 works correctly with lucide-react@0.562.0 - Comprehensive diagnostic testing shows no production runtime errors - All 1403 unit tests pass, production build succeeds - Issue likely caused by browser cache or stale Docker image (user-side) - Added troubleshooting guide for "Cannot set properties of undefined" errors ### Added - **DNS Challenge Support for Wildcard Certificates**: Full support for wildcard SSL certificates using DNS-01 challenges (Issue #21, PR #460, #461) - **Secure DNS Provider Management**: Add, edit, test, and delete DNS provider configurations with AES-256-GCM encrypted credentials - **10+ Supported Providers**: Cloudflare, AWS Route53, DigitalOcean, Google Cloud DNS, Azure DNS, Namecheap, GoDaddy, Hetzner, Vultr, DNSimple - **Automated Certificate Issuance**: Wildcard domains (e.g., `*.example.com`) automatically use DNS-01 challenges via configured providers - **Pre-Save Testing**: Test DNS provider credentials before saving to catch configuration errors early - **Dynamic Configuration**: Provider-specific credential fields with hints and documentation links - **Comprehensive Documentation**: Setup guides for major providers and troubleshooting documentation - **Security First**: Credentials never exposed in API responses, encrypted at rest with CHARON_ENCRYPTION_KEY - See [DNS Providers Guide](docs/guides/dns-providers.md) for setup instructions - **Universal JSON Template Support for Notifications**: JSON payload templates (minimal, detailed, custom) are now available for all notification services that support JSON payloads, not just generic webhooks (PR #XXX) - **Discord**: Rich embeds with colors, fields, and custom formatting - **Slack**: Block Kit messages with sections and interactive elements - **Gotify**: JSON payloads with priority levels and extras field - **Generic webhooks**: Complete control over JSON structure - **Template variables**: `{{.Title}}`, `{{.Message}}`, `{{.EventType}}`, `{{.Severity}}`, `{{.HostName}}`, `{{.Timestamp}}`, and more - See [Notification Guide](docs/features/notifications.md) for examples and migration guide - **Improved Uptime Monitoring Reliability**: Enhanced uptime monitoring system with debouncing and race condition prevention (PR #XXX) - **Failure debouncing**: Requires 2 consecutive failures before marking host as "down" to prevent false alarms from transient issues - **Increased timeout**: TCP connection timeout raised from 5s to 10s for slow networks and containers - **Automatic retries**: Up to 2 retry attempts with 2-second delay between attempts - **Synchronized checks**: All host checks complete before database reads, eliminating race conditions - **Concurrent processing**: All hosts checked in parallel for better performance - See [Uptime Monitoring Guide](docs/features/uptime-monitoring.md) for troubleshooting tips ### Changed - **Caddy Upgrade**: Upgraded Caddy from v2.10.2 to v2.11.0-beta.2 - **Dependency Cleanup**: Removed manual quic-go v0.57.1 patch (now included upstream at v0.58.0) - **Dependency Cleanup**: Removed manual smallstep/certificates v0.29.0 patch (now included upstream) - **Notification Backend Refactoring**: Renamed internal function `sendCustomWebhook` to `sendJSONPayload` for clarity (no user impact) - **Frontend Template UI**: Template configuration UI now appears for Discord, Slack, Gotify, and generic webhooks (previously webhook-only) ### Fixed - **Uptime False Positives**: Resolved issue where proxy hosts were incorrectly reported as "down" after page refresh due to timing and race conditions - **Transient Failure Alerts**: Single network hiccups no longer trigger false down notifications due to debouncing logic ### Test Coverage Improvements - **Test Coverage Improvements**: Comprehensive test coverage enhancements across backend and frontend (PR #450) - Backend coverage: **86.2%** (exceeds 85% threshold) - Frontend coverage: **87.27%** (exceeds 85% threshold) - Added SSRF protection tests for security notification handlers - Enhanced integration tests for CrowdSec, WAF, and ACL features - Improved IP validation test coverage (IPv4/IPv6 comprehensive) - See [PR #450 Implementation Summary](docs/implementation/PR450_TEST_COVERAGE_COMPLETE.md) ### Security - **Dependency Updates**: quic-go v0.58.0 with security fixes (included via Caddy v2.11.0-beta.2 upgrade) - **CRITICAL**: Complete Server-Side Request Forgery (SSRF) remediation with defense-in-depth architecture (CWE-918, PR #450) - **CodeQL CWE-918 Fix**: Resolved taint tracking issue in `url_testing.go:152` by introducing explicit variable to break taint chain - Variable `requestURL` now receives validated output from `security.ValidateExternalURL()`, eliminating CodeQL false positive - **Phase 1**: Runtime SSRF protection via `url_testing.go` with connection-time IP validation - Implemented custom `ssrfSafeDialer()` with atomic DNS resolution and IP validation - All resolved IPs validated before connection establishment (prevents DNS rebinding/TOCTOU attacks) - Validates 13+ CIDR ranges: RFC 1918 private networks, cloud metadata endpoints (169.254.0.0/16), loopback, and link-local addresses - HTTP client enforces 5-second timeout and max 2 redirects - **Phase 2**: Handler-level SSRF pre-validation in `settings_handler.go` TestPublicURL endpoint - Pre-connection validation using `security.ValidateExternalURL()` breaks CodeQL taint chain - Rejects embedded credentials (prevents URL parser differential attacks like `http://evil.com@127.0.0.1/`) - Returns HTTP 200 with `reachable: false` for SSRF blocks (maintains API contract) - Admin-only access with comprehensive test coverage (31/31 assertions passing) - **Three-Layer Defense-in-Depth Architecture**: - Layer 1: `security.ValidateExternalURL()` - URL format and DNS pre-validation - Layer 2: `network.NewSafeHTTPClient()` - Connection-time IP re-validation via custom dialer - Layer 3: Redirect validation - Each redirect target validated before following - **New SSRF-Safe HTTP Client API** (`internal/network` package): - `network.NewSafeHTTPClient()` with functional options pattern - Options: `WithTimeout()`, `WithAllowLocalhost()`, `WithAllowedDomains()`, `WithMaxRedirects()`, `WithDialTimeout()` - Prevents DNS rebinding attacks by validating IPs at TCP dial time - **Additional Protections**: - Security notification webhooks validated to prevent SSRF attacks - CrowdSec hub URLs validated against allowlist of official domains - GitHub update URLs validated before requests - **Monitoring**: All SSRF attempts logged with HIGH severity - **Validation Strategy**: Fail-fast at configuration save + defense-in-depth at request time - Pre-remediation CVSS score: 8.6 (HIGH) → Post-remediation: 0.0 (vulnerability eliminated) - CodeQL Critical finding resolved - all security tests passing - See [SSRF Protection Guide](docs/security/ssrf-protection.md) for complete documentation ### Changed - **BREAKING**: `UpdateService.SetAPIURL()` now returns error (internal API only, does not affect users) - Security notification service now validates webhook URLs before saving and before sending - CrowdSec hub sync validates hub URLs against allowlist of official domains - URL connectivity testing endpoint requires admin privileges and applies SSRF protection ### Enhanced - **Sidebar Navigation Scrolling**: Sidebar menu area is now scrollable, preventing the logout button from being pushed off-screen when multiple submenus are expanded. Includes custom scrollbar styling for better visual consistency. - **Fixed Header Bar**: Desktop header bar now remains visible when scrolling the main content area, improving navigation accessibility and user experience. ### Changed - **Repository Structure Reorganization**: Cleaned up root directory for better navigation - Moved docker-compose files to `.docker/compose/` - Moved `docker-entrypoint.sh` to `.docker/` - Moved 16 implementation docs to `docs/implementation/` - Deleted test artifacts (`block_test.txt`, `caddy_*.json`, etc.) - Added `.github/instructions/structure.instructions.md` for ongoing structure enforcement ### Added - **Bulk Apply Security Header Profiles**: Apply or remove security header profiles from multiple proxy hosts simultaneously via the Bulk Apply modal - **Standard Proxy Headers**: Charon now adds X-Real-IP, X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-Port headers to all proxy hosts by default. This enables proper client IP detection, HTTPS enforcement, and logging in backend applications. - New feature flag: `enable_standard_headers` (default: true for new hosts, false for existing) - UI: Checkbox in proxy host form with info banner explaining backward compatibility - Bulk operations: Toggle available in bulk apply modal for enabling/disabling across multiple hosts - Migration path: Existing hosts preserve old behavior (headers disabled) for backward compatibility - Note: X-Forwarded-For is handled natively by Caddy and not explicitly set by Charon ### Changed - **Backend Applications**: Applications behind Charon proxies will now receive client IP and protocol information via standard headers when the feature is enabled ### Fixed - Fixed 500 error when saving proxy hosts caused by invalid `trusted_proxies` structure in Caddy configuration - Removed redundant handler-level `trusted_proxies` (server-level configuration already provides global IP spoofing protection) - Fixed proxy host save failure (500 error) when updating enable_standard_headers, forward_auth_enabled, or waf_disabled fields - Fixed auth pass-through failure for Seerr/Overseerr caused by missing standard proxy headers ### Security - **Trusted Proxies**: Caddy configuration now always includes `trusted_proxies` directive when proxy headers are enabled, preventing IP spoofing attacks by ensuring headers are only trusted from Charon itself ### Migration Guide for Existing Users Existing proxy hosts will have standard headers **disabled by default** to maintain backward compatibility with applications that may not expect or handle these headers correctly. To enable standard headers on existing hosts: #### Option 1: Enable on individual hosts 1. Navigate to **Proxy Hosts** 2. Click **Edit** on the desired host 3. Scroll to the **Standard Proxy Headers** section 4. Check the **"Enable Standard Proxy Headers"** checkbox 5. Click **Save** #### Option 2: Bulk enable on multiple hosts 1. Navigate to **Proxy Hosts** 2. Select the checkboxes for hosts you want to update 3. Click the **"Bulk Apply"** button at the top 4. In the **Bulk Apply Settings** modal, find **"Standard Proxy Headers"** 5. Toggle the switch to **ON** 6. Check the **"Apply to selected hosts"** checkbox for this setting 7. Click **"Apply Changes"** **What do these headers do?** - **X-Real-IP**: Provides the client's actual IP address (bypasses proxy IP) - **X-Forwarded-Proto**: Indicates the original protocol (http or https) - **X-Forwarded-Host**: Contains the original Host header from the client - **X-Forwarded-Port**: Indicates the original port number used by the client - **X-Forwarded-For**: Automatically managed by Caddy (shows chain of proxies) **Why the default changed:** Most modern web applications expect these headers for proper logging, security, and functionality. New proxy hosts will have this enabled by default to follow industry best practices. **When to keep headers disabled:** - Legacy applications that don't understand proxy headers - Applications with custom IP detection logic that might conflict - Security-sensitive applications where you want to control header injection manually