Hello, I noticed that the current Ackify code has certain restrictions on redirected URLs, but these restrictions can still be bypassed by attackers.
The validation logic in HandleOIDCCallback is that if the host is not empty, it must be the same as the current host; otherwise, it allows the redirection. In fact, for URLs like /\fushuling.com, even without a host, the browser will still automatically complete the HTTP header and redirect to the external address during the actual redirection process.
I created a simple test environment based on version 1.26.0 in go.mod.
package main
import (
"log"
"net/http"
"net/url"
"os"
)
func main() {
addr := os.Getenv("LISTEN_ADDR")
if addr == "" {
addr = ":8080"
}
http.HandleFunc("/redirect", handleRedirect)
log.Printf("listening on %s (GET /redirect?next=...)", addr)
log.Fatal(http.ListenAndServe(addr, nil))
}
// handleRedirect mirrors backend/internal/presentation/api/auth/handler.go lines 155–165:
// empty next falls back to "/"; parse errors or foreign host vs r.Host force "/"; then Found redirect.
func handleRedirect(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet && r.Method != http.MethodHead {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
nextURL := r.URL.Query().Get("next")
if nextURL == "" {
nextURL = "/"
}
if parsedURL, err := url.Parse(nextURL); err != nil ||
(parsedURL.Host != "" && parsedURL.Host != r.Host) {
nextURL = "/"
}
http.Redirect(w, r, nextURL, http.StatusFound)
}
If an external address is passed in directly, the current detection logic does indeed work correctly, and it is forced to be set to /.
However, if the attacker passes in the URL /\fushuling.com, the existing validation logic will be bypassed, and the location header will be set to this URL.
When you access http://localhost:8080/redirect?next=/\fushuling.com in your actual browser, you will see that you have been successfully redirected to the external address http://fushuling.com.

Hello, I noticed that the current Ackify code has certain restrictions on redirected URLs, but these restrictions can still be bypassed by attackers.
The validation logic in
HandleOIDCCallbackis that if the host is not empty, it must be the same as the current host; otherwise, it allows the redirection. In fact, for URLs like/\fushuling.com, even without a host, the browser will still automatically complete the HTTP header and redirect to the external address during the actual redirection process.I created a simple test environment based on version 1.26.0 in go.mod.
If an external address is passed in directly, the current detection logic does indeed work correctly, and it is forced to be set to /.
However, if the attacker passes in the URL
/\fushuling.com, the existing validation logic will be bypassed, and the location header will be set to this URL.When you access
http://localhost:8080/redirect?next=/\fushuling.comin your actual browser, you will see that you have been successfully redirected to the external addresshttp://fushuling.com.