wpprobe

package
v0.12.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: MIT Imports: 10 Imported by: 0

README

WPProbe Public API

This package provides a public API for scanning WordPress sites for plugins and vulnerabilities. It's designed to be integrated into other security tools and scanners.

Quick Start

import "github.com/Chocapikk/wpprobe/pkg"

// Create scanner
scanner, err := pkg.New()
if err != nil {
    log.Fatal(err)
}

// Scan a WordPress site
result, err := scanner.Scan(pkg.Config{
    Target:   "https://example.com",
    ScanMode: "stealthy", // or "bruteforce" or "hybrid"
    Threads:  10,
    RateLimit: 5,
    Context:  context.Background(),
})

// Process results
for _, plugin := range result.Plugins {
    fmt.Printf("Plugin: %s (v%s)\n", plugin.Name, plugin.Version)
    fmt.Printf("  Critical: %d\n", len(plugin.Vulnerabilities.Critical))
    fmt.Printf("  High: %d\n", len(plugin.Vulnerabilities.High))
}

Configuration

  • Target: WordPress site URL to scan
  • ScanMode: "stealthy" (default), "bruteforce", or "hybrid"
  • Threads: Number of concurrent threads (default: 10)
  • RateLimit: Requests per second (0 = unlimited, default: 0)
  • Headers: Custom HTTP headers
  • Proxy: Proxy URL
  • PluginList: Path to plugin list file (for bruteforce/hybrid)
  • NoCheckVersion: Skip version checking
  • Context: Context for cancellation
  • ProgressCallback: Optional progress callback

Integration Examples

See example_test.go for a complete example of how to use the WPProbe API in your own tools.

Testing

Run the test script:

go run test_api.go http://localhost:9000

Documentation

Overview

Package wpprobe provides a public API for scanning WordPress sites for plugins and vulnerabilities.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func DatabaseExists

func DatabaseExists() bool

DatabaseExists checks if the Wordfence vulnerability database file exists.

func UpdateDatabases

func UpdateDatabases() error

UpdateDatabases updates both Wordfence and WPScan vulnerability databases. WPScan update requires WPSCAN_API_TOKEN environment variable to be set. Returns an error only if Wordfence update fails. WPScan update failures are ignored (WPScan is optional and requires Enterprise plan). Logging is disabled during database updates when called from the API.

Types

type Config

type Config struct {
	// Target URL to scan
	Target string

	// Scan mode: "stealthy", "bruteforce", or "hybrid"
	ScanMode string

	// Number of concurrent threads
	Threads int

	// Requests per second (0 = unlimited)
	RateLimit int

	// Custom HTTP headers (format: "Header: Value")
	Headers []string

	// Proxy URL (e.g., "http://proxy:8080")
	Proxy string

	// Maximum number of redirects to follow (0 = disable redirects, -1 = use default: 10)
	MaxRedirects int

	// Path to plugin list file (for bruteforce/hybrid modes)
	PluginList string

	// Skip version checking
	NoCheckVersion bool

	// Context for cancellation
	Context context.Context

	// Progress callback (optional)
	ProgressCallback func(message string, current, total int)

	// Enable verbose logging (default: false for API)
	Verbose bool

	// HTTPClient allows injecting an external HTTP client (e.g., from a connection pool).
	// If provided, wpprobe will use this client instead of creating its own.
	// The client should handle timeouts, TLS, and redirects as needed.
	HTTPClient *http.Client
}

Config holds configuration for a WordPress scan.

type PluginResult

type PluginResult struct {
	// Plugin slug/name
	Name string

	// Detected version
	Version string

	// Confidence score (0-100)
	Confidence float64

	// Whether the detection is ambiguous
	Ambiguous bool

	// Vulnerabilities grouped by severity
	Vulnerabilities VulnerabilitiesBySeverity
}

PluginResult represents a detected plugin with its vulnerabilities.

type ScanResult

type ScanResult struct {
	// Target URL that was scanned
	Target string

	// Detected plugins
	Plugins []PluginResult

	// Detected themes
	Themes []ThemeResult

	// Total number of vulnerabilities found
	TotalVulnerabilities int

	// Summary by severity
	Summary VulnerabilitySummary
}

ScanResult contains the complete scan results.

type Scanner

type Scanner struct{}

Scanner is the main scanner instance. It uses the global vulnerability cache to avoid memory duplication.

func New

func New() (*Scanner, error)

New creates a new Scanner instance. The scanner uses a global vulnerability cache that is loaded once and shared across all Scanner instances. This prevents memory bloat when creating many scanners. Logging is disabled during vulnerability loading when called from the API.

func (*Scanner) Reload

func (s *Scanner) Reload() error

Reload reloads vulnerabilities from the database files. Call this after UpdateDatabases() to use the newly downloaded data. Since all scanners share the global cache, this affects all Scanner instances.

func (*Scanner) Scan

func (s *Scanner) Scan(cfg Config) (*ScanResult, error)

Scan performs a WordPress scan with the given configuration.

Example

ExampleScanner_Scan demonstrates a basic WordPress scan.

package main

import (
	"context"
	"fmt"
	"log"

	wpprobe "github.com/Chocapikk/wpprobe/pkg"
)

func main() {
	// Initialize the scanner
	scanner, err := wpprobe.New()
	if err != nil {
		log.Fatalf("Failed to initialize scanner: %v", err)
	}

	// Configure the scan
	cfg := wpprobe.Config{
		Target:       "https://example.com",
		ScanMode:     "stealthy", // Options: "stealthy", "bruteforce", "hybrid"
		Threads:      10,         // Number of concurrent threads
		RateLimit:    5,          // Requests per second (0 = unlimited)
		MaxRedirects: 10,         // Maximum redirects to follow (0 = disable, -1 = default: 10)
		Context:      context.Background(),
	}

	// Perform the scan
	result, err := scanner.Scan(cfg)
	if err != nil {
		log.Fatalf("Scan failed: %v", err)
	}

	// Display results
	fmt.Printf("Scan completed for: %s\n", result.Target)
	fmt.Printf("Plugins detected: %d\n", len(result.Plugins))
	fmt.Printf("Total vulnerabilities: %d\n", result.TotalVulnerabilities)
	fmt.Printf("Severity breakdown: Critical=%d, High=%d, Medium=%d, Low=%d\n",
		result.Summary.Critical,
		result.Summary.High,
		result.Summary.Medium,
		result.Summary.Low,
	)

	// Iterate over detected plugins
	for _, plugin := range result.Plugins {
		fmt.Printf("\nPlugin: %s (v%s)\n", plugin.Name, plugin.Version)
		if len(plugin.Vulnerabilities.Critical) > 0 {
			fmt.Printf("  Critical: %d\n", len(plugin.Vulnerabilities.Critical))
		}
		if len(plugin.Vulnerabilities.High) > 0 {
			fmt.Printf("  High: %d\n", len(plugin.Vulnerabilities.High))
		}
		if len(plugin.Vulnerabilities.Medium) > 0 {
			fmt.Printf("  Medium: %d\n", len(plugin.Vulnerabilities.Medium))
		}
		if len(plugin.Vulnerabilities.Low) > 0 {
			fmt.Printf("  Low: %d\n", len(plugin.Vulnerabilities.Low))
		}
	}
}
Example (BruteforceMode)

ExampleScanner_Scan_bruteforceMode demonstrates using bruteforce scan mode.

package main

import (
	"context"
	"fmt"
	"log"

	wpprobe "github.com/Chocapikk/wpprobe/pkg"
)

func main() {
	scanner, err := wpprobe.New()
	if err != nil {
		log.Fatalf("Failed to initialize scanner: %v", err)
	}

	cfg := wpprobe.Config{
		Target:     "https://example.com",
		ScanMode:   "bruteforce",  // Brute-force mode checks thousands of plugins
		Threads:    20,            // Higher thread count for faster bruteforce
		RateLimit:  10,            // Limit rate to avoid overwhelming the server
		PluginList: "plugins.txt", // Path to plugin list file
		Context:    context.Background(),
	}

	result, err := scanner.Scan(cfg)
	if err != nil {
		log.Fatalf("Scan failed: %v", err)
	}

	fmt.Printf("Bruteforce scan completed: %d plugins found\n", len(result.Plugins))
}
Example (FilterResults)

ExampleScanner_Scan_filterResults demonstrates how to filter and process scan results.

package main

import (
	"context"
	"fmt"
	"log"

	wpprobe "github.com/Chocapikk/wpprobe/pkg"
)

func main() {
	scanner, err := wpprobe.New()
	if err != nil {
		log.Fatalf("Failed to initialize scanner: %v", err)
	}

	cfg := wpprobe.Config{
		Target:   "https://example.com",
		ScanMode: "stealthy",
		Context:  context.Background(),
	}

	result, err := scanner.Scan(cfg)
	if err != nil {
		log.Fatalf("Scan failed: %v", err)
	}

	// Filter plugins with critical vulnerabilities
	var criticalPlugins []wpprobe.PluginResult
	for _, plugin := range result.Plugins {
		if len(plugin.Vulnerabilities.Critical) > 0 {
			criticalPlugins = append(criticalPlugins, plugin)
		}
	}

	fmt.Printf("Total plugins: %d\n", len(result.Plugins))
	fmt.Printf("Plugins with critical vulnerabilities: %d\n", len(criticalPlugins))

	// Display critical CVEs
	for _, plugin := range criticalPlugins {
		fmt.Printf("\n%s (v%s) - Critical CVEs:\n", plugin.Name, plugin.Version)
		for _, vuln := range plugin.Vulnerabilities.Critical {
			fmt.Printf("  - %s: %s\n", vuln.CVE, vuln.Title)
		}
	}
}
Example (HybridMode)

ExampleScanner_Scan_hybridMode demonstrates using hybrid scan mode.

package main

import (
	"context"
	"fmt"
	"log"

	wpprobe "github.com/Chocapikk/wpprobe/pkg"
)

func main() {
	scanner, err := wpprobe.New()
	if err != nil {
		log.Fatalf("Failed to initialize scanner: %v", err)
	}

	cfg := wpprobe.Config{
		Target:     "https://example.com",
		ScanMode:   "hybrid", // Hybrid mode: stealthy first, then bruteforce
		Threads:    15,
		RateLimit:  5,
		PluginList: "plugins.txt",
		Context:    context.Background(),
	}

	result, err := scanner.Scan(cfg)
	if err != nil {
		log.Fatalf("Scan failed: %v", err)
	}

	fmt.Printf("Hybrid scan completed: %d plugins found\n", len(result.Plugins))
}
Example (WithCustomHeaders)

ExampleScanner_Scan_withCustomHeaders demonstrates scanning with custom HTTP headers.

package main

import (
	"context"
	"fmt"
	"log"

	wpprobe "github.com/Chocapikk/wpprobe/pkg"
)

func main() {
	scanner, err := wpprobe.New()
	if err != nil {
		log.Fatalf("Failed to initialize scanner: %v", err)
	}

	cfg := wpprobe.Config{
		Target:   "https://example.com",
		ScanMode: "stealthy",
		Threads:  10,
		Headers: []string{
			"User-Agent: CustomScanner/1.0",
			"X-Custom-Header: value",
		},
		Context: context.Background(),
	}

	result, err := scanner.Scan(cfg)
	if err != nil {
		log.Fatalf("Scan failed: %v", err)
	}

	fmt.Printf("Scan completed: %d plugins found\n", len(result.Plugins))
}
Example (WithProgress)

ExampleScanner_Scan_withProgress demonstrates scanning with progress tracking.

package main

import (
	"fmt"
	"log"

	wpprobe "github.com/Chocapikk/wpprobe/pkg"
)

func main() {
	scanner, err := wpprobe.New()
	if err != nil {
		log.Fatalf("Failed to initialize scanner: %v", err)
	}

	cfg := wpprobe.Config{
		Target:   "https://example.com",
		ScanMode: "stealthy",
		Threads:  10,
		ProgressCallback: func(message string, current, total int) {
			// This callback is invoked during the scan to report progress
			fmt.Printf("[%d/%d] %s\n", current, total, message)
		},
	}

	result, err := scanner.Scan(cfg)
	if err != nil {
		log.Fatalf("Scan failed: %v", err)
	}

	fmt.Printf("Scan completed: %d plugins found\n", len(result.Plugins))
}
Example (WithProxy)

ExampleScanner_Scan_withProxy demonstrates scanning through a proxy.

package main

import (
	"context"
	"fmt"
	"log"

	wpprobe "github.com/Chocapikk/wpprobe/pkg"
)

func main() {
	scanner, err := wpprobe.New()
	if err != nil {
		log.Fatalf("Failed to initialize scanner: %v", err)
	}

	cfg := wpprobe.Config{
		Target:   "https://example.com",
		ScanMode: "stealthy",
		Threads:  10,
		Proxy:    "http://proxy.example.com:8080", // Proxy URL
		Context:  context.Background(),
	}

	result, err := scanner.Scan(cfg)
	if err != nil {
		log.Fatalf("Scan failed: %v", err)
	}

	fmt.Printf("Scan completed: %d plugins found\n", len(result.Plugins))
}
Example (WithTimeout)

ExampleScanner_Scan_withTimeout demonstrates scanning with a timeout.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	wpprobe "github.com/Chocapikk/wpprobe/pkg"
)

func main() {
	scanner, err := wpprobe.New()
	if err != nil {
		log.Fatalf("Failed to initialize scanner: %v", err)
	}

	// Create a context with 30 second timeout
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	cfg := wpprobe.Config{
		Target:   "https://example.com",
		ScanMode: "stealthy",
		Threads:  5,
		Context:  ctx,
	}

	result, err := scanner.Scan(cfg)
	if err != nil {
		if err == context.DeadlineExceeded {
			log.Println("Scan timed out")
		} else {
			log.Fatalf("Scan failed: %v", err)
		}
		return
	}

	fmt.Printf("Scan completed: %d plugins found\n", len(result.Plugins))
}

type ThemeResult added in v0.11.0

type ThemeResult struct {
	// Theme slug/name
	Name string

	// Detected version
	Version string

	// Vulnerabilities grouped by severity
	Vulnerabilities VulnerabilitiesBySeverity
}

ThemeResult represents a detected theme with its vulnerabilities.

type VulnerabilitiesBySeverity

type VulnerabilitiesBySeverity struct {
	Critical []Vulnerability
	High     []Vulnerability
	Medium   []Vulnerability
	Low      []Vulnerability
}

VulnerabilitiesBySeverity groups vulnerabilities by severity level.

type Vulnerability

type Vulnerability struct {
	// CVE identifier (e.g., "CVE-2024-1234")
	CVE string

	// Title/description
	Title string

	// Severity: "critical", "high", "medium", "low"
	Severity string

	// Authentication type: "unauth", "privileged", "none"
	AuthType string

	// Affected version range
	AffectedVersion string

	// CVSS score (0-10)
	CVSSScore float64

	// CVSS vector string
	CVSSVector string
}

Vulnerability represents a single vulnerability.

type VulnerabilitySummary

type VulnerabilitySummary struct {
	Critical int
	High     int
	Medium   int
	Low      int
}

VulnerabilitySummary provides a count of vulnerabilities by severity.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL