wpscanteam/wpscan · error · WPScan::Error::AccessForbidden
The target is responding with a 403, this might be due to a
Error message
The target is responding with a 403, this might be due to a WAF. Well... --random-user-agent didn't work, use --force to skip this check if needed.
What it means
Raised by Core#check_target_availability (app/controllers/core.rb:77) when the target answers the initial GET with HTTP 403 and --force is not set. This variant is constructed with WPScan::ParsedCli.random_user_agent == true, i.e. the scan already ran with --random-user-agent and still received 403, so the message states the random UA did not help and points at --force. It almost always indicates a WAF or server-level rule (Cloudflare, ModSecurity, IP allowlist) blocking the scanner for reasons beyond the User-Agent.
Source
Thrown at app/controllers/core.rb:77
output('help', help: option_parser.full_help, simple: false) if WPScan::ParsedCli.hh
output('version') if WPScan::ParsedCli.version
exit(WPScan::ExitCode::OK) if WPScan::ParsedCli.help || WPScan::ParsedCli.hh || WPScan::ParsedCli.version
end
# Checks that the target is accessible, raises related errors otherwise.
#
# @return [ Void ]
def check_target_availability
res = WPScan::Browser.get(target.url)
case res.code
when 0
raise Error::TargetDown, res
when 401
raise Error::HTTPAuthRequired
when 403
raise Error::AccessForbidden, WPScan::ParsedCli.random_user_agent unless WPScan::ParsedCli.force
when 407
raise Error::ProxyAuthRequired
end
handle_redirection(res)
end
# Checks whether the response or its redirect chain contains a SAMLRequest,
# indicating that the target requires SAML authentication.
#
# @param [ Addressable::URI ] effective_uri Final URL after following redirects
# @param [ Typhoeus::Response ] homepage_res Response whose redirect chain to inspect
#
# @return [ Boolean ]
def saml_request?(effective_uri, homepage_res = nil)
return false unless effective_uri
return true if effective_uri.to_s.match?(/[?&]SAMLRequest/i)View on GitHub (pinned to 62c9cef471)
Solutions
- Re-run with --force to skip the 403 check if you accept scanning a site that is blocking you
- Get your scanning IP allowlisted by the site owner, or scan from an allowed network
- Route the scan through a different egress IP via --proxy that is not blocked
- If you administer the site, temporarily relax the WAF/IP rule for your IP during the scan
Example fix
# before wpscan --url http://target --random-user-agent # => ...403 ... --random-user-agent didn't work, use --force to skip this check if needed. # after wpscan --url http://target --force
Defensive patterns
Strategy: fallback
Validate before calling
# Detect the 403 block before running the scan
res = WPScan::Browser.get('http://target')
raise 'blocked (403): use --force or an allowed IP' if res.code == 403 Try / catch
begin scan.run rescue WPScan::Error::AccessForbidden => e retry_with(force: true) if e.random_user_agent_used # conscious fallback: skip the 403 check end
Prevention
- Pre-probe the target with curl to detect 403 before committing to a long scan
- Ask the site owner to allowlist the scanning IP
- Keep --force as an explicit, deliberate fallback only
- Inspect WAF headers (cf-ray, x-sucuri) in the 403 response to identify the blocker
When it happens
Trigger: `wpscan --url http://target --random-user-agent` (or random_user_agent: true in config) where WPScan::Browser.get(target.url) returns code 403: WAF rule matching scanner TLS/HTTP fingerprint, IP-based deny or allowlist, country block, or a global access rule — and no --force on the command line.
Common situations: Cloudflare/Sucuri in front of the site; ModSecurity CRS rules; nginx/apache allow-deny rules blocking the scanner IP; hosting provider blocking datacenter IP ranges; scanning through a VPN whose egress IP is blacklisted.
AI-assisted analysis of wpscanteam/wpscan@62c9cef471 (2026-08-21).
Data as JSON: /api/errors/0f2a4f728f2dc49a.
Report an issue: GitHub.