Skip to content

fix(edge): build Caddy with go-jose v4.1.6 (CVE-2026-116587) - #41

Closed
knittingcode wants to merge 4 commits into
mainfrom
fix/fcrm-sec041-caddy-modules
Closed

knittingcode wants to merge 4 commits into
mainfrom
fix/fcrm-sec041-caddy-modules

Conversation

@knittingcode

@knittingcode knittingcode commented Oct 28, 2026 •

Copy link
Copy Markdown
Owner

Summary

Builds the edge's Caddy binary with github.com/go-jose/go-jose/v4 4.1.6, which fixes CVE-2026-116587 / GHSA-mgcc-cww5-fp2q (HIGH) for v4. The docs record the triage of the part that can't be fixed yet: go-jose/v3 3.0.5, for which no fixed release exists.

This PR alone does not make the edge-prod Trivy gate pass. The v3 finding remains, and the gate correctly keeps failing on it. Resolving v3 needs an owner decision; see "Known limitations".

Motivation

  • The advisory: go-jose parses the RSA parameters of a JWK without bounds before crypto/rsa validation, so a crafted key costs cubic CPU (denial of service, CWE-407/770).
  • Affected versions:
    • v4 below 4.1.6, fixed in 4.1.6 (go-jose commit a0111f8);
    • v3 up to and including 3.0.5, the newest v3 release (OSV last_affected: 3.0.5).
  • Timing: the advisory was published by go-jose on 2026-10-14 and reviewed in the GitHub database on 2026-10-27. Since then the runtime scan of edge-prod fails whenever CI reaches it. It was first seen on PR fix(deps): update phpunit/phpunit to 13.4.5 for GHSA-9vw2-f4vp-x7gf #40 (run 40671261985). Main 999d4d1's run 40669720894 stopped earlier, at BE-03, and never reached Trivy; the same binary is on main.

Implementation

  • docker/edge/caddy/go.mod and go.sum: go get github.com/go-jose/go-jose/v4@v4.1.6 and go mod tidy.
    • No other module version changes (a 597-module before/after comparison).
    • The checksums match sum.golang.org, and go mod verify is clean.
    • The build works with the Dockerfile's -mod=readonly.
  • docs/security/container-vulnerabilities.md: a new section covering:
    • the affected and fixed versions;
    • the v3 dependency chain;
    • why a custom Caddy build can't remove v3;
    • why FlowCRM's configuration doesn't reach the vulnerable code.
  • Unchanged: no change to main.go, the Caddyfiles, the scanner, its thresholds or security/trivyignore.yaml. No exception is added.

Why not a Caddy build without caddypki

  • The import graph: modules/caddytls (internal issuer, CA pools) and caddyconfig/httpcaddyfile import caddypki directly, and modules/caddyhttp imports caddytls.
  • Consequence: every Caddy build with the HTTP app links caddypki → smallstep/certificates/authority → go.step.sm/crypto/jose → go-jose/v3.
  • Tried: a build from the modules/standard list without caddypki and acmeserver still contains v3 3.0.5 (go version -m). It drops only http.handlers.acme_server.
  • No newer releases help: go.step.sm/crypto 0.91.1 (the newest) still requires v3, and Caddy 2.11.7 and smallstep/certificates 0.30.2 are the newest releases.
  • Upstream progress: the v4 migration is open as Migrate jose from go-jose v3 to go-jose v4 smallstep/crypto#1157, not yet released.

Testing

Scans with the repo's pinned Trivy 0.67.2, using the same flags and template as tests/app/scan.sh:

Image HIGH/CRITICAL
main, edge-prod 2: v3 3.0.5 (no fix), v4 4.1.5 (fixed 4.1.6)
this branch, edge-prod 1: v3 3.0.5 (no fix)
this branch, edge-dev 1: v3 3.0.5 (no fix)

No OS-package findings in any of them.

Config validation: caddy validate passes on Caddyfile.dev, Caddyfile.prod and tests/app/https/Caddyfile. caddy adapt gives identical JSON from main and from this branch.

Container smoke tests: this branch behaves the same as main for:

  • the SPA, its client-route fallback and asset caching;
  • the common.caddy headers and request IDs;
  • FastCGI routing of /api and the health paths;
  • the security gate (503);
  • the dev reverse proxy;
  • the HTTPS test edge on 8443, 8444 and 8445.

tests/app/prodlike.sh: run in its own disposable Compose project, 39 passed, 0 failed, including the TLS and browser-over-TLS checks PL-17 to PL-23.

Repository guards: all three in scripts/ci exit 0.

Reachability, checked with the binary built exactly as the Dockerfile does:

  • the advisory's proof-of-concept request (a JWK with a 16384-bit RSA prime) sent to every HTTPS test-edge port got a 404, using about 0 CPU;
  • the control: a config that enables only acme_server spent about 2.2 s of CPU on one unauthenticated request.

Regression protection: the existing Trivy gate. Main's v4 4.1.5 fails it, so a downgrade would fail again.

CI on this head: run 40682119210 on 3f2e70b failed only at BE-03 (the PHPUnit advisory, fixed by #40). Guards 36/73/46, allocator 288/140, PHPUnit 156/278 and 53/53 negative controls passed. Frontend, stack, prod-like and Trivy were skipped after that failure, so CI has not yet shown v4 gone from the scan; the evidence above comes from local scans with the pinned Trivy. After #40 is on main, this branch needs a sync, and its CI should then fail only on the v3 finding.

Later commits: 2266471 and cf9dc3e are documentation only: the scan run IDs, a link from the older Caddy triage, and rewrapping. Run 40683504738 on the current head cf9dc3e gives the same result: it fails only at BE-03, and the later steps are skipped. Run 40683466078 on 2266471 was cancelled when the newer push superseded it.

Security considerations

  • Reachability: with this configuration, the vulnerable code isn't reachable from untrusted input. Only Caddy's acme_server handler passes untrusted JWS/JWK data to go-jose; tls internal and the pki app parse only keys Caddy creates or loads from its own configuration.
  • What FlowCRM's configs contain: no acme_server, pki, tls internal, local_certs or issuer, and admin off, auto_https off, persist_config off.
  • This is not a fix for v3, and the finding stays visible and failing.
  • Behaviour change in v4.1.6: it caps RSA JWKs at 4096 bits and rejects private keys embedded in JWS/JWE headers. FlowCRM's configuration doesn't use JOSE.

Known limitations

  • The edge-prod gate still fails on go-jose/v3 3.0.5. It can only be resolved by:
    • (a) an upstream release (smallstep/crypto and smallstep/certificates on go-jose v4, or a go-jose v3.0.6);
    • (b) a narrowly scoped, time-limited exception for v3 only, which needs an owner decision and isn't part of this PR.
  • Two more medium v3 advisories (GHSA-4w3g-jfj2-cw2q, GHSA-vvm8-gf78-28g4) have been published by go-jose but aren't yet in the global database. Trivy will likely report them later.
  • Possibly unrelated: govulncheck lists golang.org/x/net 0.60.0 (GO-2026-6866, GO-2026-6860; fixed in 0.62.0). It is imported but not called, and Trivy doesn't flag it HIGH/CRITICAL.

go-jose v4.1.5 in the rebuilt Caddy binary is affected by
CVE-2026-116587 (GHSA-mgcc-cww5-fp2q, DoS when parsing JWKs with RSA
keys); 4.1.6 fixes it. go.mod and go.sum updated with go get and
go mod tidy; go mod verify is clean.
Record that the go-jose v4 path is fixed and that go-jose v3 3.0.5
stays: it is linked through caddypki, which caddytls, httpcaddyfile and
therefore caddyhttp import, so no Caddy module selection removes it.
State why FlowCRM's configuration does not reach the code and that the
finding still fails the edge prod gate.
@knittingcode

Copy link
Copy Markdown
Owner Author

Superseded by #42 (squash commit 1badf76). Verified against main 1badf76: docker/edge/caddy/go.mod and go.sum are byte-identical to this PR's head cf9dc3e (go-jose/v4 4.1.6). The CVE-2026-116587 section of docs/security/container-vulnerabilities.md is in main, extended by #42. The only sentence of this PR not kept is the one saying the finding fails the gate until an exception is decided; ADR-021, accepted on 2026-10-28, replaced it. Closed without merging; the branch is kept.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant