This file provides guidance to AI coding agents when working with code in this repository.
WPScan is a WordPress security scanner written in Ruby. It provides WordPress-specific scanning capabilities including vulnerability detection, enumeration, and password attacks.
Key characteristics:
- Ruby gem with CLI tool
- Architecture based on Controllers, Finders, and Models (MVC-like pattern)
- Uses local database (in
$XDG_CACHE_HOME/wpscan/dbor~/.cache/wpscan/db, or~/.wpscan/dbfor existing installations) that syncs with WPScan API - Scanner framework lives in
lib/wpscan/(Target, Browser, Controller::Base, Scan, Finders, Formatter, etc.) alongside the WordPress-specific code - Supports WordPress-specific security scanning features
- Always run rubocop after making changes to ensure code style compliance
- Run
bundle exec rubocop -ato auto-fix issues - For specific files:
bundle exec rubocop -a file1.rb file2.rb - The project uses RuboCop for Ruby style enforcement
bundle install# Run all tests except slow ones (default for PRs)
bundle exec rspec --tag ~slow
# Run full test suite (includes slow tests, only runs on master)
bundle exec rspec
# Run specific test file
bundle exec rspec spec/path/to/file_spec.rb
# Run with coverage
bundle exec rspec # Coverage enabled by default via .simplecov# Run rubocop
bundle exec rubocop
# Auto-fix rubocop issues
bundle exec rubocop -a
# IMPORTANT: Always run rubocop after making code changes
# Run on specific files being modified:
bundle exec rubocop -a path/to/file1.rb path/to/file2.rb# Build the gem (runs rubocop & rspec automatically)
bundle exec rake build
# Install gem locally
gem install pkg/wpscan-*.gem# From source (outside git repo to avoid load path conflicts)
ruby -Ilib bin/wpscan --url https://example.com
# Or after installing as gem
wpscan --url https://example.com# Update local database
wpscan --update
# The database is stored in $XDG_CACHE_HOME/wpscan/db or ~/.cache/wpscan/db (new installations)
# or ~/.wpscan/db (existing installations)Entry Point:
bin/wpscan- CLI executable that chains controllers together- Controllers are chained using
<<operator and executed in order
Controllers (app/controllers/):
Controllers orchestrate the scanning process. The Core controller (app/controllers/core.rb) is implicitly handled by the scanner framework via WPScan::Scan.new and runs before the explicitly chained controllers. The explicit chain in bin/wpscan executes in this order:
VulnApi- API token setup for vulnerability dataCustomDirectories- Custom wp-content/plugins directory detectionInterestingFindings- Header analysis, robots.txt, readme filesWpVersion- WordPress version detectionMainTheme- Active theme detectionEnumeration- Plugins, themes, users, etc (see CLI options)PasswordAttack- Brute force attacksAliases- Handle legacy CLI options
Note: The Core controller handles database updates, WordPress detection, and banner display during the before_scan phase.
Finders (app/finders/): Finders implement detection strategies for various WordPress components. Each finder type has multiple strategies (passive, aggressive, mixed):
WpVersion- Detects WordPress versionMainTheme- Detects active themePlugins- Plugin enumeration strategiesThemes- Theme enumeration strategiesUsers- User enumeration (author ID brute forcing, API endpoints, etc)InterestingFindings- Backup files, debug logs, etcConfigBackups- Config backup file detection (wp-config.php backups)DbExports- Database export file detectionMedias- Media/attachment enumeration via brute forcingTimthumbs- Timthumb script detection at known locationsPasswords- Authentication mechanisms (wp-login, XML-RPC)
Models (app/models/): Domain objects representing WordPress components:
WpItem- Base class for plugins/themesPlugin,Theme- Specific WordPress itemsWpVersion- WordPress version with vulnerability infoInterestingFinding- Security-relevant findingsConfigBackup- Detected wp-config.php backup filesDbExport- Detected database export filesMedia- Media attachments found on the siteTimthumb- Timthumb script instancesXMLRPC- XML-RPC interface details
Database (lib/wpscan/db/):
Updater- Syncs local database with WPScan APIVulnApi- API client for vulnerability dataDynamicFinders- Auto-generated finders from database metadataFingerprints- Version detection fingerprints- Database stored in
$XDG_CACHE_HOME/wpscan/db/or~/.cache/wpscan/db/(new installations) or~/.wpscan/db/(existing installations) by default (overridden in specs tospec/fixtures/db/)
Scanner framework:
The scanner framework lives under WPScan:: alongside the WordPress-specific code. Core framework classes — WPScan::Target, WPScan::Browser, WPScan::Controller::{Base,Core}, WPScan::ParsedCli, WPScan::Vulnerability, WPScan::Model::{InterestingFinding,XMLRPC}, etc. — are single unified classes, not split across framework/WordPress layers. WordPress-specific behavior is mixed in via modules (e.g. WPScan::Target::Platform::WordPress is included into WPScan::Target). Option parsing delegates to the external opt_parse_validator gem.
Dynamic Finders:
Finders can be dynamically generated from database metadata (see lib/wpscan/db/dynamic_finders/). This allows version detection strategies to be data-driven.
Slug Classification:
WordPress slugs (plugin/theme names) are converted to Ruby class names via classify_slug helper (lib/wpscan/helper.rb). Handles edge cases:
- Slugs starting with digits get prefixed with
D_(e.g.,123-pluginbecomesD_123Plugin) - Special characters are converted to underscores
- Slugs with all non-latin characters become
HexSlug_followed by hex-encoded bytes
API Requests Tracking:
The codebase tracks API requests via WPScan.api_requests class variable to monitor usage against API limits.
- Tests use RSpec with WebMock for HTTP stubbing
- Fixtures in
spec/fixtures/ - Shared examples in
spec/shared_examples/ - Coverage via SimpleCov (configured in
.simplecov)
rspec_parsed_options(args)- Parse CLI argumentsdf_expected_all- Dynamic finder test expectationsvuln_api_data_for(path)- Load vulnerability API fixturesredefine_constant(constant, value)- Override WPScan constants for testing
--tag ~slow- Excludes slow tests (default for CI on PRs)- Full suite runs only on master pushes
Active Support Must Be First:
active_support/all must be required before other gems to avoid encoding issues with JSON (see lib/wpscan.rb:4-6).
Running Outside Git Repo:
When using wpscan from source, run it outside the git repo to avoid load path conflicts.
Database Location:
Tests override DB_DIR to spec/fixtures/db/. Production uses $XDG_CACHE_HOME/wpscan/db or ~/.cache/wpscan/db (new installations) or ~/.wpscan/db (existing installations).
Port Normalization: WebMock adapter has custom port normalization for Typhoeus (spec/spec_helper.rb:63-96) to handle default ports.
WPScan API:
- Requires API token (via
--api-tokenorWPSCAN_API_TOKENenv var or config file) - Free tier: 25 requests/day
- One request per WordPress version, plugin, and theme detected
- Response tracking via
Typhoeus.on_completehook in lib/wpscan.rb
Configuration Files: WPScan loads options from (in order):
$XDG_CONFIG_HOME/wpscan/scan.jsonor$XDG_CONFIG_HOME/wpscan/scan.yml(ifXDG_CONFIG_HOMEis set)~/.config/wpscan/scan.jsonor~/.config/wpscan/scan.yml(ifXDG_CONFIG_HOMEis not set)~/.wpscan/scan.jsonor~/.wpscan/scan.ymlpwd/.wpscan/scan.jsonorpwd/.wpscan/scan.yml
Use snake_case for CLI options in config (e.g., api_token, max_threads).