Back to skill

Security audit

Wp Login

Security checks for vulnerabilities and agentic risk

Overview

This WordPress login skill has a coherent purpose, but it handles credentials and authenticated sessions with under-disclosed persistence and weakened browser security settings.

Review this before installing or running. Use it only with a trusted WordPress site, preferably over valid HTTPS, and avoid running the bundled test script as written. Expect local files such as screenshots, wp-state.json, and puppeteer_user_data to contain sensitive session or admin-page information unless the skill is revised to make those artifacts opt-in, protected, and cleaned up.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
test-login.js:1
Finding
Agent Configuration File Loaded into the Process Environment## Vulnerability Details **File Location**: `test-login.js:1` **Vulnerability Type**: Excessive access to Agent configuration **Risk Level**: High ### Vulnerable Code ```js require('dotenv').config({ path: '/Users/denis/.openclaw/openclaw.json' }); ``` ### Technical Analysis The test script directs `dotenv` to parse a hard-coded OpenClaw configuration file rather than a narrowly scoped environment file. Any compatible entries parsed from this file may be copied into `process.env`, where the application and loaded third-party dependencies can access them. The documented task requires only `WP_URL`, `WP_USER`, and `WP_PASSWORD`. Reading a broader Agent configuration file violates least privilege and unnecessarily expands the set of potentially sensitive values available to the process. Because the file is an absolute user-specific path, the script also reaches outside the project directory. ### Attack Path 1. A user runs `test-login.js` on a system where `/Users/denis/.openclaw/openclaw.json` exists. 2. `dotenv` opens and attempts to parse the Agent configuration file. 3. Compatible entries are imported into the Node.js process environment. 4. The application or any loaded dependency can inspect the imported environment values. 5. If unrelated secrets are present and successfully parsed, they become exposed beyond the code that legitimately needs them. ### Impact Assessment This behavior may expose unrelated Agent configuration values and credentials to the login script and its dependency graph. The scope is limited to values readable by the current operating-system user and successfully parsed by `dotenv`; the code does not itself transmit those values to an external endpoint. Nevertheless, a compromised dependency or future code change could abuse the broadened access.
Remediation
## Remediation Suggestions - Remove the hard-coded OpenClaw configuration path. - Prefer supplying `WP_URL`, `WP_USER`, and `WP_PASSWORD` directly through the runtime environment. - If a file is necessary, use a dedicated project-local environment file containing only the three required values. - Validate and copy only an explicit allowlist of required variables. - Ensure the credential file has owner-only permissions and is excluded from version control. - Avoid making unrelated configuration values available to browser automation dependencies.

T09 · Insecure Skill Coding Practices

Error
Location
index.js:9
Finding
TLS Certificate Validation Disabled for WordPress Login## Vulnerability Details **File Location**: `index.js:9-19` **Vulnerability Type**: Disabled HTTPS certificate verification **Risk Level**: High ### Vulnerable Code ```js const context = await browser.newContext({ userAgent: '...', viewport: { width: 1280, height: 800 }, locale: 'fr-FR', timezoneId: 'Europe/Paris', permissions: ['geolocation'], reducedMotion: 'no-preference', javaScriptEnabled: true, bypassCSP: true, ignoreHTTPSErrors: true, }); ``` ### Technical Analysis Setting `ignoreHTTPSErrors: true` instructs Playwright to accept invalid, expired, mismatched, or untrusted TLS certificates. The same browser context subsequently submits the WordPress username and password and receives authenticated cookies. HTTPS encryption without certificate authentication does not establish that the remote server is the intended WordPress instance. An attacker able to intercept or redirect traffic can present an untrusted certificate that the browser accepts. ### Attack Path 1. An attacker gains a network interception or DNS-redirection position between the browser and `WP_URL`. 2. The attacker presents a certificate that would normally fail validation. 3. Playwright accepts the certificate because `ignoreHTTPSErrors` is enabled. 4. The counterfeit server presents a compatible WordPress login form. 5. The script fills and submits `WP_USER` and `WP_PASSWORD`. 6. The attacker captures the credentials and may also manipulate or capture the resulting session. ### Impact Assessment A successful interception can disclose the full WordPress username and password, enabling access with all privileges assigned to that account. If the account is an administrator, the attacker may gain administrative control of the WordPress site. Authenticated session cookies and content returned during the session may also be compromised.
Remediation
## Remediation Suggestions - Remove `ignoreHTTPSErrors: true` or explicitly set it to `false`. - Require an HTTPS `WP_URL` for any non-local deployment. - If a private certificate authority is used, install and trust that specific CA instead of disabling verification globally. - Validate that the final navigation origin remains the configured origin before filling credentials. - Reject unexpected redirects to different hosts. - Consider restricting accepted URL schemes to `https:` and allow insecure HTTP only through an explicit development-only option.

T09 · Insecure Skill Coding Practices

Error
Location
index.js:49
Finding
Authenticated WordPress Session State Persisted to a Predictable Plaintext File## Vulnerability Details **File Location**: `index.js:49-53` **Vulnerability Type**: Insecure storage of authenticated session material **Risk Level**: High ### Vulnerable Code ```js if (page.url().includes('/wp-admin/')) { console.log('Login réussi avec Playwright !'); // Sauvegarde storage state pour réutiliser await context.storageState({ path: 'wp-state.json' }); return true; } ``` ### Technical Analysis After a successful login, Playwright serializes the browser context state to `wp-state.json` in the current working directory. Storage-state files can contain cookies and origin storage associated with the authenticated session. The code does not apply restrictive file permissions, encryption, expiration handling, user consent, or cleanup. The predictable project-relative path increases the likelihood that the file will be read by another local process, collected as an artifact, included in a backup, or accidentally committed to source control. ### Attack Path 1. The skill successfully authenticates to WordPress. 2. Playwright exports the browser context to `wp-state.json`. 3. A local user, process, backup service, artifact collector, or repository operation obtains the file. 4. The party imports usable cookies or storage values into another browser context. 5. If the server-side session remains valid and is not otherwise bound to the original client, the party impersonates the WordPress user without knowing the password. ### Impact Assessment Exposure can permit session hijacking with the privileges of the authenticated WordPress account until the session expires or is revoked. For an administrator account, this could expose site administration functions. Exploitability depends on the contents of the generated state, local file access, server-side session validity, and any additional session-binding controls.
Remediation
## Remediation Suggestions - Do not persist browser state by default. - Require explicit user opt-in before exporting an authenticated session. - If persistence is required, write to a user-private directory rather than the project directory. - Create the destination with owner-only permissions and verify permissions after writing. - Encrypt sensitive state at rest where practical. - Delete the file as soon as reuse is no longer required and provide a documented revocation procedure. - Add `wp-state.json` and any alternative state filenames to version-control and artifact ignore rules. - Prefer short-lived, least-privileged WordPress accounts for automation.

T09 · Insecure Skill Coding Practices

Warning
Location
implementation.js:27
Finding
Persistent Puppeteer Profile Retains Browser and Authentication Data## Vulnerability Details **File Location**: `implementation.js:27-34` **Vulnerability Type**: Undisclosed persistent storage of browser state **Risk Level**: Medium ### Vulnerable Code ```js console.log('Launching Puppeteer with persistent profile'); const userDataDir = path.resolve('./puppeteer_user_data'); const browser = await puppeteerExtra.launch({ headless: true, userDataDir, }); ``` ### Technical Analysis Puppeteer is launched with a fixed `userDataDir` inside the current project directory. A persistent Chromium profile can retain cookies, local storage, cache, browsing history, and other site data across executions. This is not required for a one-time login check and is not disclosed in the skill documentation. Although the function attempts to log out before logging in, logout does not guarantee that all browser data, historical session artifacts, caches, or storage values are securely removed. The function also returns immediately on successful login without closing the browser, increasing the duration for which the authenticated profile remains active and writable. ### Attack Path 1. `loginWordPress()` starts Chromium with `./puppeteer_user_data`. 2. The browser logs into the configured WordPress site. 3. Chromium stores browser and potentially authenticated state in the persistent profile. 4. Another local party copies or reads the profile directory. 5. The party extracts or reuses any still-valid session information retained in the profile. ### Impact Assessment A party with local read access may obtain browsing metadata or reusable authentication material. Successful session reuse would grant the privileges of the WordPress account for the remaining session lifetime. The exact impact depends on Chromium’s retained data, WordPress session validity, and local filesystem permissions.
Remediation
## Remediation Suggestions - Use an ephemeral browser profile by default and allow Puppeteer to clean it up when the browser closes. - Require explicit opt-in when profile persistence is a functional requirement. - Store persistent profiles outside the project tree in a user-private directory with owner-only permissions. - Close the browser in a `finally` block on every return path, including successful login. - Clear cookies, local storage, cache, and other site data when persistence is no longer needed. - Exclude `puppeteer_user_data` from version control, backups, and build artifacts. - Document the retention period and provide a secure deletion mechanism.

T09 · Insecure Skill Coding Practices

Warning
Location
index.js:34
Finding
Diagnostic Screenshots Persist Potentially Sensitive Login and Administration Content## Vulnerability Details **File Locations**: `index.js:34`, `index.js:46`, `implementation.js:55`, `implementation.js:68`, and `implementation.js:72` **Vulnerability Type**: Insecure diagnostic artifact storage **Risk Level**: Medium ### Vulnerable Code From `index.js`: ```js await page.screenshot({ path: 'playwright_initial.png' }); await page.fill('#user_login', user); await page.fill('#user_pass', password); await Promise.all([ page.click('#wp-submit'), page.waitForNavigation({ waitUntil: 'domcontentloaded' }) ]); await page.screenshot({ path: 'playwright_after_submit.png' }); ``` From `implementation.js`: ```js if (loginError) { const errorMessage = await page.evaluate(el => el.textContent, loginError); console.error('Login error detected:', errorMessage.trim()); await page.screenshot({ path: 'login-error.png' }); console.log('Screenshot saved: login-error.png'); return false; } const loggedIn = await page.$('#wp-admin-bar-my-account, #wpadminbar, #wpbody-content'); if (loggedIn) { console.log('Login successful'); return true; } console.log('Login elements not found on the page'); await page.screenshot({ path: `login-failed-attempt-${attempt + 1}.png` }); console.log(`Screenshot saved: login-failed-attempt-${attempt + 1}.png`); } catch (err) { console.error('Error during login attempt:', err); await page.screenshot({ path: `error-attempt-${attempt + 1}.png` }); console.log(`Screenshot saved: error-attempt-${attempt + 1}.png`); } ``` ### Technical Analysis The code writes screenshots to predictable filenames in the current working directory. The post-submit screenshot can capture authenticated WordPress administration pages, usernames, account notices, site data, plugin information, or other private content. Error screenshots may capture server messages or values reflected by the page. The script does not request consent, restrict file permis ...[truncated 1209 chars]
Remediation
## Remediation Suggestions - Disable screenshots by default and require explicit diagnostic opt-in. - Avoid capturing authenticated administration pages unless strictly necessary. - Mask or redact usernames, notices, tokens, URLs, and sensitive page regions before capture. - Store diagnostics in a protected temporary directory with owner-only permissions and unpredictable filenames. - Automatically delete screenshots after the diagnostic session or after a short documented retention period. - Exclude all screenshot patterns from version control, build artifacts, and automated uploads. - Log only minimal metadata needed to diagnose a failure.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill is designed to collect and use sensitive credentials from environment variables and perform an HTTP login flow, but it provides no explicit warning about secure handling of those secrets, trusted target validation, or logging risks. In agent environments, this increases the chance that credentials are used against an unintended WordPress instance, exposed through misconfiguration, or handled insecurely by downstream tooling.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The code launches Puppeteer with a persistent `userDataDir`, which stores cookies, session tokens, and other browser state on disk. In an automation skill that logs into WordPress, this creates a real risk of unintended retention and reuse of authenticated sessions, especially because there is no user-facing warning, consent, lifecycle control, or cleanup of the stored profile.

Missing User Warnings

Medium
Confidence
82% confidence
Finding
The skill accepts a username and password and automatically submits them to an arbitrary `url`, with no validation of destination or explicit disclosure that credentials will be transmitted. In context, this is functional login automation, but it is still security-sensitive because a caller could direct it to an unintended or attacker-controlled endpoint, causing credential exposure.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The code accesses WP_URL, WP_USER, and WP_PASSWORD directly from environment variables, which is a sensitive operation under the warning criteria for code files. While the file logs login success/failure later, there is no prompt, comment, or user-facing disclosure around credential access itself in these lines.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The code hard-codes locale 'fr-FR' and timezone 'Europe/Paris', which is a natural-language locale policy concern when no opt-in or justification is provided. This can impose a specific language/region behavior on users regardless of their preferences or environment.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The browser context enables capabilities that weaken normal security boundaries for a simple WordPress login helper, most notably `bypassCSP: true` and `ignoreHTTPSErrors: true`. If the target site or network path is malicious or compromised, these settings increase exposure to injected scripts, man-in-the-middle attacks, and broader data capture than the login task requires.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script saves screenshots before and after login and persists authenticated session state to `wp-state.json`. These artifacts can capture usernames, admin pages, cookies, and other session material that may allow account takeover or sensitive information disclosure if the local filesystem is accessible to other users, processes, or later exfiltration.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The script loads environment variables from a hard-coded user-specific path in the home directory, which strongly suggests access to local secrets outside the project boundary. This is risky because it implicitly depends on and consumes potentially sensitive credentials without transparency, portability, or validation, and could expose or misuse personal tokens if the script is shared or run in another environment.