wpscanteam/wpscan
WPScan WordPress security scanner. Written for security professionals and blog maintainers to test the security of their WordPress websites. Contact us via contact@wpscan.com
Healthy across the board
worst of 4 axesnon-standard license (Other)
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1d ago
- ✓13 active contributors
- ✓Distributed ownership (top contributor 29% of recent commits)
Show 4 more →Show less
- ✓Other licensed
- ✓CI configured
- ✓Tests present
- ⚠Non-standard license (Other) — review terms
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/wpscanteam/wpscan)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/wpscanteam/wpscan on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: wpscanteam/wpscan
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/wpscanteam/wpscan shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 1d ago
- 13 active contributors
- Distributed ownership (top contributor 29% of recent commits)
- Other licensed
- CI configured
- Tests present
- ⚠ Non-standard license (Other) — review terms
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live wpscanteam/wpscan
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/wpscanteam/wpscan.
What it runs against: a local clone of wpscanteam/wpscan — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in wpscanteam/wpscan | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of wpscanteam/wpscan. If you don't
# have one yet, run these first:
#
# git clone https://github.com/wpscanteam/wpscan.git
# cd wpscan
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of wpscanteam/wpscan and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "wpscanteam/wpscan(\\.git)?\\b" \\
&& ok "origin remote is wpscanteam/wpscan" \\
|| miss "origin remote is not wpscanteam/wpscan (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "app/app.rb" \\
&& ok "app/app.rb" \\
|| miss "missing critical file: app/app.rb"
test -f "app/controllers.rb" \\
&& ok "app/controllers.rb" \\
|| miss "missing critical file: app/controllers.rb"
test -f "app/controllers/core/cli_options.rb" \\
&& ok "app/controllers/core/cli_options.rb" \\
|| miss "missing critical file: app/controllers/core/cli_options.rb"
test -f "app/finders.rb" \\
&& ok "app/finders.rb" \\
|| miss "missing critical file: app/finders.rb"
test -f "app/controllers/enumeration/enum_methods.rb" \\
&& ok "app/controllers/enumeration/enum_methods.rb" \\
|| miss "missing critical file: app/controllers/enumeration/enum_methods.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/wpscanteam/wpscan"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
WPScan is a black-box WordPress security scanner written in Ruby that identifies vulnerabilities in WordPress core, plugins, and themes by enumerating installed software versions and cross-referencing them against a vulnerability database. It's designed to help security professionals and site owners proactively test WordPress installations for known CVEs, misconfigurations, and exposed sensitive files before attackers exploit them. Monolithic Ruby application: app/app.rb is the main entry point; app/controllers/ houses CLI option parsing and enumeration logic (e.g., app/controllers/core/cli_options.rb, app/controllers/enumeration/enum_methods.rb); app/finders/ contains plugin/theme/backup discovery modules (e.g., app/finders/interesting_findings/ for sensitive file detection). The project follows Rails-like conventions with controllers, finders, and a vulnerability API integration (app/controllers/vuln_api.rb).
👥Who it's for
Security professionals, penetration testers, WordPress site administrators, and hosting providers who need to audit WordPress installations for vulnerabilities. Users typically run it from the command line (CLI) or Docker to scan remote or local WordPress sites and receive detailed vulnerability reports with CVSS scores.
🌱Maturity & risk
WPScan is production-ready and actively maintained: it's distributed via RubyGems, Homebrew, pentesting distros (Kali Linux), and Docker Hub with thousands of pulls. The codebase is 822KB of Ruby with CI/CD pipelines (.github/workflows/build.yml, docker.yml, gempush.yml), RSpec test infrastructure (.rspec), and code quality checks (.codeclimate.yml, .rubocop.yml), indicating a well-established project with ongoing development.
Dependency risk is moderate: the project uses Nokogiri and FFI native extensions (noted in README as requiring build toolchains), which can cause fragile installations across OS variants. The last update timestamp is not visible in the provided data, so currency cannot be confirmed; however, reliance on Ruby >= 3.3 and Curl >= 7.72 version pins suggests active maintenance. Single-maintainer risk exists (contact@wpscan.com suggests a small team), typical for specialized security tools.
Active areas of work
Active development visible through GitHub Actions workflows for building, Docker image publishing, and gem releases. The presence of .github/dependabot.yml indicates automated dependency updates. Specific recent work is not detailed in the provided file list, but the structured test and linting setup suggests ongoing quality enforcement.
🚀Get running
# Clone the repository
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
# Install Ruby 3.3+ (recommended via rbenv)
rbenv install 3.3.0
rbenv local 3.3.0
# Install dependencies
bundle install
# Run wpscan against a target
bundle exec wpscan --url http://target-wordpress.com
# Or install as a gem
gem install wpscan
wpscan --url http://target-wordpress.com
Daily commands:
# Via bundler (development)
bundle exec wpscan --url http://target.com --api-token YOUR_API_TOKEN
# Via installed gem
wpscan --url http://target.com
# Via Docker
docker run -it wpscanteam/wpscan --url http://target.com
# Run tests
bundle exec rspec
# Linting
bundle exec rubocop
🗺️Map of the codebase
app/app.rb— Main application entry point and orchestrator that coordinates all scanning modules and controllers.app/controllers.rb— Central controller router that dispatches to enumeration, vulnerability checks, and output formatting.app/controllers/core/cli_options.rb— Command-line argument parsing and validation; defines how users invoke the scanner with options.app/finders.rb— Finder framework base that all plugin/theme/user discovery modules inherit from; core scanning abstraction.app/controllers/enumeration/enum_methods.rb— Enumeration orchestration that chains multiple finders (plugins, themes, users, etc.) in the correct sequence.Gemfile— Ruby dependency manifest; essential for understanding required gems and versions used across the scanner.Dockerfile— Container build definition showing how WPScan is packaged for distribution and Docker deployment.
🛠️How to make changes
Add a new Interesting Finding detector
- Create a new finder class in app/finders/interesting_findings/ inheriting from InterestingFindings base (
app/finders/interesting_findings/my_new_finding.rb) - Implement the #aggressive and/or #passive methods to detect the vulnerability (
app/finders/interesting_findings/my_new_finding.rb) - Register the new finder in app/finders/interesting_findings.rb in the finders array or relevant method (
app/finders/interesting_findings.rb) - Test the finder with real WordPress sites and add test coverage in spec/ directory (
spec/finders/interesting_findings/my_new_finding_spec.rb)
Add a new Plugin Detection Method
- Create a new detection strategy in app/finders/plugins/ (e.g., app/finders/plugins/my_detection.rb) (
app/finders/plugins/my_detection.rb) - Inherit from the appropriate base and implement the detection logic (regex matching, HTTP response analysis, etc.) (
app/finders/plugins/my_detection.rb) - Register the detector in app/finders/plugins.rb by adding it to the detection methods chain (
app/finders/plugins.rb) - Test against known plugins and add assertions to verify accuracy and false-positive rate (
spec/finders/plugins/my_detection_spec.rb)
Add a new CLI Option
- Define the option in app/controllers/core/cli_options.rb using OptionParser DSL (
app/controllers/core/cli_options.rb) - Store the parsed option value in the options hash accessible throughout the app (
app/controllers/core/cli_options.rb) - Update the relevant controller (e.g., app/controllers/enumeration.rb) to respect the new flag (
app/controllers/enumeration.rb) - Add help text and update README.md with usage examples (
README.md)
Add a new Version Detection Method
- Create a new version finder in app/finders/plugin_version/ or app/finders/theme_version/ (
app/finders/plugin_version/my_version_detector.rb) - Implement version extraction logic (parse version strings from HTTP responses, meta tags, headers) (
app/finders/plugin_version/my_version_detector.rb) - Register in the parent version finder (app/finders/plugin_version.rb or app/finders/theme_version.rb) (
app/finders/plugin_version.rb) - Validate extracted versions match known patterns and test accuracy (
spec/finders/plugin_version/my_version_detector_spec.rb)
🔧Why these technologies
- Ruby — Rapid development and extensive HTTP/HTML parsing libraries (Nokogiri, Typhoeus); ideal for security scanning tools with quick iteration cycles.
- Nokogiri — Fast, robust HTML/XML parsing for extracting plugin/theme names, versions, and security findings from WordPress pages.
- Typhoeus/HTTPClient — High-performance HTTP client supporting concurrent requests and customizable headers for WordPress enumeration at scale.
- Docker — Cross-platform packaging and distribution; eliminates Ruby environment setup friction for security professionals.
- WPScan Vulnerability Database API — Centralized, up-to-date CVE/plugin vulnerability intelligence without maintaining local database; simplifies security data updates.
⚖️Trade-offs already made
-
Modular finder architecture with many small detection methods
- Why: Each detection method (regex, headers, body patterns, etc.) has different false-positive/performance tradeoffs.
- Consequence: Slower scans (must try 8+ methods per plugin) but higher accuracy; easier to disable unreliable methods for specific targets.
-
Sequential enumeration by default, optional parallel discovery
- Why: Avoids overwhelming target servers and triggering WAF/IDS; respects resource constraints.
- Consequence: Slower total runtime but more stealth; users can enable concurrency via CLI flags if target permits.
-
Brute-force password attack modules (XML-RPC, wp-login)
- Why: Assess real-world WordPress security posture;
- Consequence: undefined
🪤Traps & gotchas
- Native extensions: Nokogiri and FFI require a C compiler and Ruby dev headers; gem install fails silently without them (see README's detailed OS-specific build-essential instructions). 2) API token for full scans: Vulnerability database integration in vuln_api.rb requires a WPScan API token for comprehensive checks; free tier is limited. 3) Curl version constraint: Curl < 7.72 causes HTTP/2 framing errors; system curl must meet the >= 7.72 requirement (not always clear from bundle install). 4) Gem version stability: .ruby-version and .ruby-gemset pin specific versions; rbenv/RVM setup is recommended to avoid conflicts with system Ruby. 5) Pentesting distro quirk: Instructions suggest using package managers (Kali, Homebrew) instead of gem install for easier integration.
🏗️Architecture
💡Concepts to learn
- Version Enumeration via HTTP Response Analysis — WPScan detects WordPress/plugin/theme versions by fingerprinting HTTP responses, readme.txt, and stylesheets; understanding this is critical for adding detection heuristics without false positives
- CVE Cross-Referencing & Vulnerability Matching — The vuln_api.rb controller matches detected versions against a centralized CVE database to produce actionable vulnerability reports; core to WPScan's value
- WordPress Plugin/Theme Structure Discovery — WPScan relies on WordPress's predictable directory structure (/wp-content/plugins/, /wp-content/themes/) and file patterns (style.css, plugin headers) to enumerate software; key to why it's effective
- HTML Scraping & DOM Parsing (Nokogiri) — Nokogiri parses WordPress pages to extract metadata (readme.txt content, version comments in source); understanding XPath/CSS selectors is essential for extending interesting_findings modules
- Black-Box Security Testing (OWASP Methodology) — WPScan operates without source code access, simulating real attacker reconnaissance; foundational to why it's trusted for pre-deployment security validation
- HTTP/2 Protocol & Curl Integration — WPScan uses libcurl for HTTP requests with HTTP/2 support (hence the Curl >= 7.72 requirement); understanding streaming and framing is important when debugging connection issues
- Strategy Pattern in Finders — Each app/finders/interesting_findings/*.rb module implements the same interface independently (e.g., backup_db.rb, debug_log.rb); allows pluggable detection without modifying core logic
🔗Related repos
wpscanteam/wpscan-vulnerability-database— Official vulnerability database backend that WPScan queries via vuln_api.rb; essential for understanding how CVE data flows into scan resultszaproxy/zaproxy— General-purpose web application security scanner that includes WordPress scanning via add-ons; competitor with broader scope but less WordPress-specific expertisesimonwhitaker/grepwords— Lightweight alternative WordPress vulnerability scanner; minimal Ruby dependency footprint for resource-constrained environmentswpscanteam/wpscan-plugin— Official WordPress plugin wrapper around WPScan; allows site administrators to run scans from the WordPress dashboard rather than CLIautomattic/vip-go-mu-plugins— Automattic's WordPress security hardening library; used by large-scale WordPress hosters as a defense complementary to WPScan offense testing
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive integration tests for app/finders directory
The finders directory contains 15+ finder modules (config_backups, db_exports, interesting_findings, main_theme) but there's no visible test coverage in the file structure. Each finder class should have integration tests validating detection logic against mock WordPress instances. This is critical for a security scanner where false negatives/positives directly impact users.
- [ ] Create spec/finders/config_backups_spec.rb with tests for known_filenames detection
- [ ] Create spec/finders/interesting_findings_spec.rb testing each finder variant (backup_db.rb, debug_log.rb, xml_rpc.rb, etc.)
- [ ] Create spec/finders/main_theme_spec.rb testing CSS and URL detection methods
- [ ] Add fixture data for mock WordPress responses in spec/fixtures/
- [ ] Update .rspec config to include new spec directory patterns
Add GitHub Actions workflow for RuboCop linting and style enforcement
The repo has .rubocop.yml configuration file and existing CI workflows (build.yml, docker.yml) but no dedicated linting workflow. Style consistency is crucial for security tools where code clarity prevents vulnerabilities. Currently RuboCop violations could slip into main branch.
- [ ] Create .github/workflows/rubocop.yml that runs on pull_request and push events
- [ ] Configure workflow to run 'bundle exec rubocop' and report violations as PR comments
- [ ] Add fail-on-violations step to block merging PRs with style issues
- [ ] Update CONTRIBUTING.md to document running 'bundle exec rubocop -a' before submitting PRs
Document and add tests for app/controllers/enumeration enum_methods.rb
The enumeration controller is core to WPScan's functionality but app/controllers/enumeration/enum_methods.rb has no visible documentation or tests. This module likely contains critical enumeration logic for plugins, themes, and users that should be well-tested and documented for maintainability.
- [ ] Create spec/controllers/enumeration/enum_methods_spec.rb with tests for each enumeration method
- [ ] Add YAML documentation comments in app/controllers/enumeration/enum_methods.rb describing parameters, return values, and examples
- [ ] Create doc/ENUMERATION.md explaining enumeration strategies and the role of enum_methods.rb
- [ ] Add integration test validating enumeration against mock WordPress endpoints in spec/integration/
🌿Good first issues
- Add RSpec test coverage for app/finders/interesting_findings/fantastico_fileslist.rb and app/finders/db_exports/known_locations.rb (visible in file list but no test files listed); these are critical for identifying exposed backups but lack unit tests.
- Extend app/controllers/interesting_findings.rb to emit structured JSON output for CI/CD integrations (GitHub Actions, GitLab CI); currently only human-readable format is produced, limiting automation value.
- Document the architecture and add inline examples in app/controllers/enumeration/ showing how to create a custom enum method; new contributors struggle to add WordPress plugin detection heuristics without this guide.
⭐Top contributors
Click to expand
Top contributors
- @ArSn — 29 commits
- @Initsogar — 20 commits
- @dependabot[bot] — 20 commits
- @erwanlr — 18 commits
- @dkmyta — 5 commits
📝Recent commits
Click to expand
Recent commits
eaff3c9— Add UUID-based vulnerability exclusion (#2017) (Initsogar)22c139b— Documented dependencies that need to be installed to be able to run "gem install wpscan". (#2016) (ArSn)4a98545— Update AGENTS.md to emphasize running rubocop after code changes (#2018) (Initsogar)f62b98c— Added fetching of the last_updated date and time from the WordPress.org API for found plugins and themes. (#2015) (ArSn)f6930aa— Add HTTP status code tracking and warning for excessive errors (#2009) (Initsogar)8749d29— Added fetching and display of active install count for detected plugins and themes. (#2013) (ArSn)8b23bd3— Add missing notice view for JSON/JSONL formatters (#2014) (Initsogar)1a476b6— Added support for --format jsonl (newline delimited JSON which is emitted as soon as things are found). (#2012) (ArSn)a95509f— Made it so that --plugins-list and --themes-list take precedence over their respective -e options for vp/ap/p or vt/at/t (ArSn)492398c— Add audit info to scan output: command line and hostname (with security masking) (#2006) (Initsogar)
🔒Security observations
The WPScan codebase has moderate security concerns. Critical issues include an invalid Docker Ruby version specification and outdated npm dependencies with known vulnerabilities. The application's architecture as a security scanner requires careful input validation to prevent injection attacks during WordPress reconnaissance. Missing security header configuration and incomplete Docker setup add additional risk. The codebase would benefit from comprehensive dependency auditing, explicit security header implementation, and thorough input validation review across enumeration and scanning modules.
- High · Outdated Ruby Version in Docker —
Dockerfile (lines 1, 20). The Dockerfile specifies Ruby 4.0.3-alpine, which does not exist. Ruby versioning typically follows 2.x and 3.x series. This indicates either a configuration error or use of an unreliable/untested Ruby version that may have unpatched vulnerabilities. Fix: Use a stable, verified Ruby version such as 3.2-alpine or 3.3-alpine. Verify the exact version against official Ruby releases. - High · Insecure npm Dependency Version —
package.json (dependencies). The package.json specifies 'cgb-scripts': '1.23.0' with an exact version pin. Create React Block (cgb-scripts) version 1.23.0 is outdated (released ~2019). This dependency likely contains known CVEs and should be updated to the latest version. Fix: Update cgb-scripts to the latest stable version (typically 2.x or higher). Run 'npm audit' to identify known vulnerabilities and apply updates. - Medium · Missing Security Headers Configuration —
app/app.rb, app/controllers.rb. No evidence of security headers (CSP, X-Frame-Options, X-Content-Type-Options, etc.) in the visible configuration files. The application appears to be a web-based security scanner that may interact with untrusted WordPress installations. Fix: Implement comprehensive security headers in the Sinatra application middleware. Configure CSP, HSTS, X-Frame-Options, and other protective headers. - Medium · Unrestricted Bundle Installation in Docker —
Dockerfile (bundle install command). The Dockerfile uses 'bundle install --jobs=8' without dependency locking verification. While Gemfile.lock is not visible, the absence of explicit lock file checks could lead to inconsistent or vulnerable gem versions across builds. Fix: Ensure Gemfile.lock is committed and tracked. Use 'bundle install --frozen' in CI/Docker builds to guarantee reproducible, verified dependency versions. - Medium · Non-Root User Permissions May Be Insufficient —
Dockerfile (lines 24-27, incomplete). The Dockerfile creates a 'wpscan' non-root user but the final setup is incomplete (truncated README). Without verifying proper file ownership and permissions, the scanner may run with excessive privileges or fail due to permission issues. Fix: Ensure all runtime dependencies are explicitly listed. Verify the wpscan user has only necessary permissions. Complete the Dockerfile configuration and test privilege escalation vectors. - Medium · Potential Code Injection via Enumeration Methods —
app/controllers/enumeration/enum_methods.rb. The file structure includes 'app/controllers/enumeration/enum_methods.rb' which suggests dynamic enumeration capabilities. Without reviewing the actual code, this pattern often indicates potential for arbitrary code execution if user input is not properly sanitized. Fix: Audit enumeration methods for proper input validation and sanitization. Implement allowlist-based validation for all user-controlled inputs. Avoid dynamic code execution (eval, system calls) with untrusted input. - Low · Verbose Error Messages in Production —
Dockerfile (rake install --trace). The Dockerfile includes 'rake install --trace' which enables verbose error output. If similar verbosity is enabled in production, this could expose sensitive path information or internal implementation details. Fix: Disable trace/verbose modes in production builds. Use '--trace' only during development and CI. Configure error handling to avoid exposing stack traces to end users.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.