Skip to content
27 changes: 25 additions & 2 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,29 @@ func Test_Set_Config_To_Request(t *testing.T) {
}

func Test_Client_SetProxyURL(t *testing.T) {
httpProxy := os.Getenv("HTTP_PROXY")
httpProxyLower := os.Getenv("http_proxy")
httpsProxy := os.Getenv("HTTPS_PROXY")
httpsProxyLower := os.Getenv("https_proxy")
noProxy := os.Getenv("NO_PROXY")
noProxyLower := os.Getenv("no_proxy")

require.NoError(t, os.Unsetenv("HTTP_PROXY"))
require.NoError(t, os.Unsetenv("http_proxy"))
require.NoError(t, os.Unsetenv("HTTPS_PROXY"))
require.NoError(t, os.Unsetenv("https_proxy"))
require.NoError(t, os.Unsetenv("NO_PROXY"))
require.NoError(t, os.Unsetenv("no_proxy"))

t.Cleanup(func() {
require.NoError(t, os.Setenv("HTTP_PROXY", httpProxy))
require.NoError(t, os.Setenv("http_proxy", httpProxyLower))
require.NoError(t, os.Setenv("HTTPS_PROXY", httpsProxy))
require.NoError(t, os.Setenv("https_proxy", httpsProxyLower))
require.NoError(t, os.Setenv("NO_PROXY", noProxy))
require.NoError(t, os.Setenv("no_proxy", noProxyLower))
})

t.Parallel()

app, dial, start := createHelperServer(t)
Expand All @@ -1603,7 +1626,7 @@ func Test_Client_SetProxyURL(t *testing.T) {
DisablePathNormalizing: true,
}

// Create a simple proxy sever
// Create a simple proxy server
proxyServer := fiber.New()

proxyServer.Use("*", func(c fiber.Ctx) error {
Expand Down Expand Up @@ -1664,7 +1687,7 @@ func Test_Client_SetProxyURL(t *testing.T) {
t.Parallel()
client := New()

err := client.SetProxyURL(":this is not a proxy")
err := client.SetProxyURL("http://127.0.0.1:1")
require.NoError(t, err)

_, err = client.Get("http://localhost:3000")
Expand Down
61 changes: 60 additions & 1 deletion middleware/static/static.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package static

import (
"errors"
"fmt"
"io/fs"
"net/url"
"os"
pathpkg "path"
"path/filepath"
"strconv"
"strings"
Expand All @@ -14,6 +17,57 @@ import (
"github.com/valyala/fasthttp"
)

// sanitizePath validates and cleans the requested path.
// It returns an error if the path attempts to traverse directories.
func sanitizePath(p []byte, filesystem fs.FS) ([]byte, error) {
// convert backslashes to slashes for consistency
s := strings.ReplaceAll(string(p), "\\", "/")

// repeatedly unescape until it no longer changes, catching errors
for {
if !strings.Contains(s, "%") {
break
}
us, err := url.PathUnescape(s)
if err != nil {
return nil, errors.New("invalid path")
}
if us == s {
break
}
s = us
}

// reject any null bytes or traversal attempts
if strings.Contains(s, "\x00") || strings.Contains(s, "..") || strings.Contains(s, ":") {
Comment thread
gaby marked this conversation as resolved.
Outdated
return nil, errors.New("invalid path")
}

raw := s
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
s = pathpkg.Clean("/" + s)

if filesystem != nil {
s = strings.TrimPrefix(s, "/")
if s == "" {
return []byte("/"), nil
}
Comment thread
gaby marked this conversation as resolved.
if !fs.ValidPath(s) {
return nil, errors.New("invalid path")
}
s = "/" + s
} else {
// verify no traversal after cleaning
if strings.Contains(raw, "..") || strings.Contains(s, "..") {
return nil, errors.New("invalid path")
}
Comment thread
gaby marked this conversation as resolved.
Outdated
if !strings.HasPrefix(s, "/") {
s = "/" + s
}
}
Comment thread
gaby marked this conversation as resolved.
Outdated

return utils.UnsafeBytes(s), nil
}

// New creates a new middleware handler.
// The root argument specifies the root directory from which to serve static assets.
//
Expand Down Expand Up @@ -108,7 +162,12 @@ func New(root string, cfg ...Config) fiber.Handler {
path = append([]byte("/"), path...)
}

return path
sanitized, err := sanitizePath(path, fs.FS)
if err != nil {
// return a guaranteed-missing path so fs responds with 404
return []byte("/__fiber_invalid__")
}
return sanitized
Comment thread
gaby marked this conversation as resolved.
}

maxAge := config.MaxAge
Expand Down
Loading
Loading