🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

github.com/labstack/echo/v4

Package Overview
Dependencies
Versions
509
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

github.com/labstack/echo/v4 - go Package Compare versions

Comparing version
v4.15.1
to
v4.15.2
+1
-3
.github/workflows/checks.yml

@@ -17,3 +17,3 @@ name: Run checks

# run static analysis only with the latest Go version
LATEST_GO_VERSION: "1.25"
LATEST_GO_VERSION: "1.26"

@@ -48,3 +48,1 @@ jobs:

govulncheck ./...

@@ -17,3 +17,3 @@ name: Run Tests

# run coverage and benchmarks only with the latest Go version
LATEST_GO_VERSION: "1.25"
LATEST_GO_VERSION: "1.26"

@@ -29,3 +29,3 @@ jobs:

# we derive from last four major releases promise.
go: ["1.22", "1.23", "1.24", "1.25"]
go: ["1.25", "1.26"]
name: ${{ matrix.os }} @ Go ${{ matrix.go }}

@@ -32,0 +32,0 @@ runs-on: ${{ matrix.os }}

# Changelog
## v4.15.2 - 2026-05-01
**Security**
* `Context.Scheme()` should validate values taken from header by @aldas in https://github.com/labstack/echo/pull/2962
Thanks to @shblue21 for reporting this [issue](https://github.com/labstack/echo/issues/2952).
## v4.15.1 - 2026-02-22
**Enhancements**
* CSRF: support older token-based CSRF protection handler that want to render token into template by @aldas in https://github.com/labstack/echo/pull/2905
## v4.15.0 - 2026-01-01

@@ -4,0 +20,0 @@

@@ -907,56 +907,172 @@ // SPDX-License-Identifier: MIT

func TestContext_Scheme(t *testing.T) {
tests := []struct {
c Context
s string
var testCases = []struct {
name string
givenIsTLS bool
givenHeaders http.Header
expect string
}{
{
&context{
request: &http.Request{
TLS: &tls.ConnectionState{},
},
name: "defaults to http without TLS or headers",
givenIsTLS: false,
givenHeaders: nil,
expect: "http",
},
{
name: "returns https when TLS is enabled",
givenIsTLS: true,
givenHeaders: nil,
expect: "https",
},
{
name: "TLS takes precedence over forwarded proto",
givenIsTLS: true,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"http"},
},
"https",
expect: "https",
},
{
&context{
request: &http.Request{
Header: http.Header{HeaderXForwardedProto: []string{"https"}},
},
name: "uses X-Forwarded-Proto http",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"http"},
},
"https",
expect: "http",
},
{
&context{
request: &http.Request{
Header: http.Header{HeaderXForwardedProtocol: []string{"http"}},
},
name: "uses X-Forwarded-Proto https",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"https"},
},
"http",
expect: "https",
},
{
&context{
request: &http.Request{
Header: http.Header{HeaderXForwardedSsl: []string{"on"}},
},
name: "X-Forwarded-Proto is case insensitive",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"HTTPS"},
},
"https",
expect: "HTTPS",
},
{
&context{
request: &http.Request{
Header: http.Header{HeaderXUrlScheme: []string{"https"}},
},
name: "uses X-Forwarded-Proto ws",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"ws"},
},
"https",
expect: "ws",
},
{
&context{
request: &http.Request{},
name: "uses X-Forwarded-Proto wss",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"wss"},
},
"http",
expect: "wss",
},
{
name: "ignores invalid X-Forwarded-Proto and uses X-Forwarded-Protocol",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"ftp"},
HeaderXForwardedProtocol: []string{"https"},
},
expect: "https",
},
{
name: "uses X-Forwarded-Protocol",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProtocol: []string{"https"},
},
expect: "https",
},
{
name: "X-Forwarded-Proto takes precedence over X-Forwarded-Protocol",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"http"},
HeaderXForwardedProtocol: []string{"https"},
},
expect: "http",
},
{
name: "uses X-Forwarded-Ssl on",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedSsl: []string{"on"},
},
expect: "https",
},
{
name: "X-Forwarded-Ssl on is case sensitive",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedSsl: []string{"ON"},
},
expect: "http",
},
{
name: "X-Forwarded-Protocol takes precedence over X-Forwarded-Ssl",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProtocol: []string{"http"},
HeaderXForwardedSsl: []string{"on"},
},
expect: "http",
},
{
name: "uses X-Url-Scheme",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXUrlScheme: []string{"https"},
},
expect: "https",
},
{
name: "X-Forwarded-Ssl takes precedence over X-Url-Scheme",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedSsl: []string{"on"},
HeaderXUrlScheme: []string{"http"},
},
expect: "https",
},
{
name: "ignores invalid forwarded headers and falls back to http",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{"ftp"},
HeaderXForwardedProtocol: []string{"smtp"},
HeaderXForwardedSsl: []string{"off"},
HeaderXUrlScheme: []string{"file"},
},
expect: "http",
},
{
name: "ignores empty forwarded proto and uses X-Url-Scheme",
givenIsTLS: false,
givenHeaders: http.Header{
HeaderXForwardedProto: []string{""},
HeaderXUrlScheme: []string{"https"},
},
expect: "https",
},
}
for _, tt := range tests {
assert.Equal(t, tt.s, tt.c.Scheme())
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/", nil)
if tc.givenHeaders != nil {
req.Header = tc.givenHeaders
}
e := New()
c := e.NewContext(req, nil)
if tc.givenIsTLS {
c.Request().TLS = &tls.ConnectionState{}
}
assert.Equal(t, tc.expect, c.Scheme())
})
}

@@ -963,0 +1079,0 @@ }

@@ -275,2 +275,15 @@ // SPDX-License-Identifier: MIT

func isValidProto(proto string) bool {
if proto == "" {
return false
}
for _, p := range []string{"http", "https", "ws", "wss"} {
if strings.EqualFold(proto, p) {
return true
}
}
return false
}
// Scheme returns the HTTP protocol scheme, `http` or `https`.
func (c *context) Scheme() string {

@@ -282,6 +295,6 @@ // Can't use `r.Request.URL.Scheme`

}
if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" {
if scheme := c.request.Header.Get(HeaderXForwardedProto); isValidProto(scheme) {
return scheme
}
if scheme := c.request.Header.Get(HeaderXForwardedProtocol); scheme != "" {
if scheme := c.request.Header.Get(HeaderXForwardedProtocol); isValidProto(scheme) {
return scheme

@@ -292,3 +305,3 @@ }

}
if scheme := c.request.Header.Get(HeaderXUrlScheme); scheme != "" {
if scheme := c.request.Header.Get(HeaderXUrlScheme); isValidProto(scheme) {
return scheme

@@ -295,0 +308,0 @@ }

@@ -270,3 +270,3 @@ // SPDX-License-Identifier: MIT

// Version of Echo
Version = "4.15.0"
Version = "4.15.2"
website = "https://echo.labstack.com"

@@ -273,0 +273,0 @@ // http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo

+8
-8
module github.com/labstack/echo/v4
go 1.24.0
go 1.25.0
require (
github.com/labstack/gommon v0.4.2
github.com/labstack/gommon v0.5.0
github.com/stretchr/testify v1.11.1
github.com/valyala/fasttemplate v1.2.2
golang.org/x/crypto v0.46.0
golang.org/x/net v0.48.0
golang.org/x/time v0.14.0
golang.org/x/crypto v0.50.0
golang.org/x/net v0.53.0
golang.org/x/time v0.15.0
)

@@ -17,8 +17,8 @@

github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-isatty v0.0.22 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/text v0.36.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+14
-15
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c=
github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

@@ -17,13 +17,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=

github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=

@@ -30,0 +29,0 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=