diff --git a/ui/components/scans/scans-page-shell.test.tsx b/ui/components/scans/scans-page-shell.test.tsx
index 0c402b76ed..6906207516 100644
--- a/ui/components/scans/scans-page-shell.test.tsx
+++ b/ui/components/scans/scans-page-shell.test.tsx
@@ -329,6 +329,51 @@ describe("ScansPageShell", () => {
expect(screen.getByRole("dialog")).toHaveTextContent(/launch scan/i);
});
+ it("does not open the launch scan modal from the URL when no provider is connected", () => {
+ vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
+ searchParamsValue.current = "launchScan=true";
+
+ render(
+
+ Scans table
+ ,
+ );
+
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
+ });
+
+ it("does not open the launch scan modal from client state when no provider is connected", () => {
+ vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
+ useScansStore.getState().openLaunchScanModal();
+
+ render(
+
+ Scans table
+ ,
+ );
+
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
+ });
+
+ it("does not open the launch scan modal from the URL without manage scans permission", () => {
+ vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
+ searchParamsValue.current = "launchScan=true";
+
+ render(
+
+ Scans table
+ ,
+ );
+
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
+ });
+
it("strips the launchScan URL param via the History API when closing the URL-opened modal", async () => {
vi.stubEnv("NEXT_PUBLIC_IS_CLOUD_ENV", "false");
searchParamsValue.current = "tab=completed&launchScan=true";
diff --git a/ui/components/scans/scans-page-shell.tsx b/ui/components/scans/scans-page-shell.tsx
index 634ed2d330..56cf315077 100644
--- a/ui/components/scans/scans-page-shell.tsx
+++ b/ui/components/scans/scans-page-shell.tsx
@@ -75,7 +75,8 @@ export function ScansPageShell({
const showProvidersHint = thereAreNoProviders || !hasConnectedProviders;
const isCloudEnvironment = isCloud();
const launchDisabled = !hasManageScansPermission || !hasConnectedProviders;
- const launchOpen = isLaunchScanModalOpen || urlLaunchOpen;
+ const launchOpen =
+ !launchDisabled && (isLaunchScanModalOpen || urlLaunchOpen);
// When a scan is already running, the tour highlights its row (anchored in
// ScanJobsTable); otherwise it falls back to the Launch Scan button + tabs.
const hasInProgressScan = activeScanCount > 0;