diff --git a/lib/NGCP/Panel/Controller/Root.pm b/lib/NGCP/Panel/Controller/Root.pm index b13dbe2e6f..86caad3e74 100644 --- a/lib/NGCP/Panel/Controller/Root.pm +++ b/lib/NGCP/Panel/Controller/Root.pm @@ -11,6 +11,7 @@ use NGCP::Panel::Utils::DateTime qw(); use NGCP::Panel::Utils::Statistics qw(); use NGCP::Panel::Utils::Auth; use NGCP::Panel::Form qw(); +use NGCP::Panel::Utils::Navigation qw(); use DateTime qw(); use Time::HiRes qw(); use DateTime::Format::RFC3339 qw(); @@ -453,7 +454,8 @@ sub back :Path('/back') :Args(0) { } else { $target = $c->uri_for('/dashboard'); } - $c->response->redirect($target); + + $c->response->redirect(NGCP::Panel::Utils::Navigation::check_target($c,$target)); $c->detach; } diff --git a/lib/NGCP/Panel/Utils/Navigation.pm b/lib/NGCP/Panel/Utils/Navigation.pm index f8de7ed798..3a0b639df9 100644 --- a/lib/NGCP/Panel/Utils/Navigation.pm +++ b/lib/NGCP/Panel/Utils/Navigation.pm @@ -89,10 +89,33 @@ sub select_back_target { sub back_or { my ($c, $alternative_target, $nodetach) = @_; my $target = select_back_target($c, $alternative_target); - $c->response->redirect($target); + $c->response->redirect(check_target($c, $target)); $c->detach unless($nodetach); } +sub check_target { + + my ( $c, $target ) = @_; + + my $safe_fallback = $c->uri_for('/dashboard'); + return $safe_fallback unless $target; + + my $uri_checker = ref($target) eq 'URI' ? $target : URI->new($target); + + if ($uri_checker->can('host') && $uri_checker->host) { + # Check both host and port to prevent cross-port redirects + if ($uri_checker->host_port ne $c->req->uri->host_port) { + $c->log->warn("Blocked external redirect: " . $uri_checker->as_string); + return $safe_fallback; + } + } + + # todo: check for host header injection + + return $target; + +} + 1; =head1 NAME