Tags: labstack/echo
Tags
Merge commit from fork * fix: trust forwarded scheme headers only from trusted proxies Context.Scheme() used X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl and X-Url-Scheme from any client, so a direct client could send X-Forwarded-Proto: https over plain HTTP and bypass middleware.HTTPSRedirect() (GHSA-2ffq-g2xg-c22p). The headers are now used only when the request comes directly from a loopback, link-local or private network address or a unix socket. Echo#SchemeExtractor (and Config.SchemeExtractor) selects the strategy: ExtractSchemeFromHeaders (default, accepts TrustOption), ExtractSchemeDirect, or LegacySchemeExtractor for the old behavior. The Secure middleware now uses Context.Scheme() for HSTS, and the Proxy middleware always sets X-Forwarded-Proto from Context.Scheme() instead of forwarding a client-supplied value. * fix(proxy): always set X-Real-IP from Context.RealIP() The Proxy middleware forwarded a client-supplied X-Real-IP header to the upstream when Echo#IPExtractor was not set, so any client could spoof the IP address seen by upstream services (GHSA-99jh-6h7p-pp36). Since v5.1.0, Context.RealIP() returns the address of the direct peer unless Echo#IPExtractor is configured, so the header is now always set from Context.RealIP(). * fix: validate JSONP callback and send nosniff header Context.JSONP and Context.JSONPBlob wrote the callback into the response unchanged, so a callback taken from a query parameter could inject arbitrary JavaScript (GHSA-h9g5-28mm-hx3g). The callback must now be empty, a JavaScript identifier or a dot-separated path of identifiers (ASCII letters, digits, _ and $). Otherwise nothing is written and a 400 Bad Request error wrapping ErrInvalidJSONPCallback is returned. JSONP responses also get the X-Content-Type-Options: nosniff header. Claude-Session: https://claude.ai/code/session_01QKDYQr53zNKkR7nif2CAAq * fix(method-override): do not override POST to safe methods MethodOverride rewrote a POST to any method, including GET and HEAD. When the middleware ran before CSRF, a cross-site form POST with _method=GET skipped the CSRF check (GHSA-r7w9-592q-9vg4). POST can no longer be overridden to GET, HEAD, OPTIONS, TRACE or CONNECT. The documentation now also says to register the middleware with Echo#Pre. Claude-Session: https://claude.ai/code/session_01QKDYQr53zNKkR7nif2CAAq * fix: percent-encode control characters in redirect paths The trailing slash middlewares and the static directory redirect only collapsed a leading double slash. Browsers remove tab and newline characters from URLs, so a path such as /%09/evil.example/ produced Location: /\t/evil.example/, which a browser follows to evil.example (GHSA-v753-g4cw-jm48). sanitizeURI now percent-encodes C0 control characters and DEL before the double slash check, so the browser requests the same path. Claude-Session: https://claude.ai/code/session_01QKDYQr53zNKkR7nif2CAAq * fix(static): resolve files from the routed path and reject dot segments The Static middleware resolved files from the decoded URL.Path while the router matched the escaped URL.RawPath, so /admin%2Fsecret.txt or /%61dmin/secret.txt reached a file under a guarded /admin/* route (GHSA-375p-5qhx-8wq4). It now uses the same form of the path as the router and unescapes it only when EnablePathUnescaping is set. Both the Static middleware and StaticDirectoryHandler (Echo.Static, Echo.StaticFS) resolved file names with path.Clean(), while the router matched the path as sent. A path with a ".", ".." or empty segment, such as /assets/../admin/secret.txt, could therefore reach a file under a route the router never matched (GHSA-3pmx-cf9f-34xr). Such paths are no longer served. The documented opt-in behavior of encoded dots with path unescaping enabled is unchanged. Claude-Session: https://claude.ai/code/session_01QKDYQr53zNKkR7nif2CAAq * docs: changelog for security release and Static middleware guard note Claude-Session: https://claude.ai/code/session_01QKDYQr53zNKkR7nif2CAAq * fix: harden security fixes after review - Scheme: when X-Forwarded-Proto is present, use only it (its last value, added by the nearest proxy) instead of falling back to other headers, and return the scheme in lowercase so HTTPSRedirect and HSTS work with "HTTPS". - Proxy: remove X-Forwarded-Ssl, X-Forwarded-Protocol and X-Url-Scheme before forwarding; X-Forwarded-Proto carries the scheme. - Static: check for dot segments again after path unescaping, keep the HTML5 index fallback for unclean paths, check the path only once, and document how EnablePathUnescaping affects non-default escaping. - Tests: guardable route-level static test, group static test, and a control-character redirect test that does not rely on traversal. - Docs: IPExtractor default, SchemeExtractor trust notes, changelog behavior changes; bump Version to 5.4.0. Claude-Session: https://claude.ai/code/session_01QKDYQr53zNKkR7nif2CAAq * docs: set v5.4.0 release date Claude-Session: https://claude.ai/code/session_01QKDYQr53zNKkR7nif2CAAq
PreviousNext