wpscanteam/wpscan · error · WPScan::Error::BrowserFailed

SAML authentication needs an interactive terminal to wait fo

Error message

SAML authentication needs an interactive terminal to wait for login, but stdin is not a TTY. Run wpscan from a real shell when using --expect-saml.

What it means

WPScan::Error::BrowserFailed raised at the top of BrowserAuthenticator.authenticate (lib/wpscan/browser_authenticator.rb:13-17) when --expect-saml is used and $stdin is not a TTY. The SAML flow opens a visible browser, waits for you to complete the IdP login, then blocks on a bare 'gets' for you to press enter; without an interactive stdin that handshake is impossible, so it fails fast before launching anything.

Source

Thrown at lib/wpscan/browser_authenticator.rb:14

# frozen_string_literal: true

require 'ferrum'

module WPScan
  module BrowserAuthenticator
    # Characters that, if present in a cookie name or value, would corrupt the
    # serialized Cookie header. Per RFC 6265 these are forbidden in cookie-octets,
    # but a noncompliant IdP could still emit them.
    COOKIE_DELIMITERS = /[;,\s]/

    def self.authenticate(login_url)
      unless $stdin.tty?
        raise WPScan::Error::BrowserFailed,
              'SAML authentication needs an interactive terminal to wait for login, but stdin is not a TTY. ' \
              'Run wpscan from a real shell when using --expect-saml.'
      end

      cookies = run_login_session(login_url)

      raise WPScan::Error::SAMLAuthenticationFailed if cookies.nil? || cookies.empty?

      serialize_cookies(cookies)
    end

    # Drives the interactive browser session and returns the resulting cookie jar.
    # Translates Ferrum failures into BrowserFailed with a context-specific message.
    def self.run_login_session(login_url)
      browser = Ferrum::Browser.new(headless: false)

      puts 'SAML authentication needed. Log in via the browser window that just opened, then press enter.'
      browser.goto(login_url)

View on GitHub (pinned to 62c9cef471)

Solutions

  1. Run wpscan --expect-saml from a real interactive shell (stdin attached to a terminal)
  2. For containers/ssh allocate a TTY: docker run -it ... or ssh -t
  3. For automation, drop --expect-saml and authenticate another way the target permits (e.g. --http-auth) or capture cookies once interactively and reuse them per your setup
  4. If scripting the gem, gate the call: only enable SAML handling when $stdin.tty? is true

Example fix

# before (CI job, stdin is not a TTY)
$ wpscan --url https://example.com --expect-saml
# => BrowserFailed: SAML authentication needs an interactive terminal ...

# after (interactive shell)
$ wpscan --url https://example.com --expect-saml
# browser opens, log in, press enter in the terminal
Defensive patterns

Strategy: validation

Validate before calling

# Gate the SAML flow on interactivity before invoking the scanner
unless $stdin.tty?
  abort '--expect-saml needs an interactive terminal; re-run from a real shell or drop the flag'
end

Try / catch

begin
  WPScan::BrowserAuthenticator.authenticate(login_url)
rescue WPScan::Error::BrowserFailed => e
  abort e.message # TTY problem or browser problem: neither is retryable in-process
end

Prevention

When it happens

Trigger: Calling WPScan with expect_saml enabled from cron, systemd, CI runners, nohup, a piped shell (wpscan ... < file, curl ... | wpscan), ssh without -t, or a Docker container started without -t; programmatically calling WPScan::BrowserAuthenticator.authenticate(login_url) in a test or daemon where $stdin has been redirected.

Common situations: Trying to automate SAML-authenticated scans headlessly; running wpscan inside a pipeline stage; scheduled tasks that were tested interactively first; running under a process supervisor (supervisord, Kubernetes job) where stdin is /dev/null.

Understand the failure class

Related errors


AI-assisted analysis of wpscanteam/wpscan@62c9cef471 (2026-08-21). Data as JSON: /api/errors/dde5d2aea1d50867. Report an issue: GitHub.