Security
How to responsibly report a vulnerability, how we respond, and the public record of past advisories.
Reporting a vulnerability
If you believe you have found a security issue in PerfLocale, please report it to us privately first so we can investigate and issue a fix before the details become public. This protects every site running PerfLocale while we work on a patch.
Email: [email protected]
In your report, please include as much of the following as you can:
- A description of the issue and why you believe it's a security problem.
- Steps to reproduce it on a fresh WordPress install with PerfLocale active. A minimal proof-of-concept helps us confirm the scope.
- The PerfLocale version, WordPress version, and PHP version you tested against.
- Any ideas you have for mitigation or a fix. These are always welcome but never required.
Please don't open a public GitHub issue, a WordPress.org forum post, or a blog post about the vulnerability before we've had a chance to fix it. Coordinated disclosure keeps users safe.
How reports are handled
PerfLocale is maintained by one person, so please treat response times as best-effort rather than a service commitment. Reports are read and triaged as soon as I can get to them, and I will tell you whether I consider the issue a valid security problem before doing anything else.
Once a fix is released, I am happy to credit you by whatever name, handle, or company you prefer — just say so in your report. If you would rather not be named, you won’t be.
Scope
In scope:
- The PerfLocale WordPress plugin source code as published on WordPress.org.
- The bundled first-party addons under
addons/in the plugin. - The plugin's REST endpoints, admin pages, and frontend output when processing attacker-controlled input.
Out of scope:
- Third-party plugins and themes that PerfLocale integrates with (report those to the respective vendors).
- WordPress core issues (report those to WordPress's HackerOne program).
- This marketing website (
perflocale.com) - unless the issue allows attacking plugin users directly. - Issues that require an already-compromised administrator account, physical access to the server, or social engineering.
- Missing security headers on static documentation pages, absent rate limiting on public blog endpoints, or similar best-practice recommendations without a demonstrable exploit.
Server hardening you should check
Two things depend on your web server rather than on the plugin, and PerfLocale cannot fix either from PHP.
The export directory
A data export is a full dump of your translation data. It is written to wp-content/uploads/perflocale/exports/ under a filename carrying 32 characters of randomness, and it is downloaded through an authenticated, nonce-checked admin link that deletes the file as soon as it has been served. PerfLocale also writes a Deny from all .htaccess beside it.
Apache and LiteSpeed honour that file. nginx and Caddy ignore it entirely. On those servers an export that has been generated but not yet downloaded is fetchable by anyone who has its exact URL, until it is downloaded or swept. The filename is not guessable, but a URL can leak through access logs, browser history, a referrer header, a support screenshot or a backup. Add an explicit rule:
location ~* /wp-content/uploads/perflocale/exports/ {
deny all;
return 404;
}@perflocale_exports path /wp-content/uploads/perflocale/exports/*
respond @perflocale_exports 404You do not have to guess which case you are in. Tools → Site Health writes a temporary random file into that directory, requests it over HTTP the way a stranger would, and raises a critical result — with the snippet above — if the server hands it back. The test file is deleted immediately either way, and the result is cached for an hour.
On a host that blocks loopback requests and does not persist transients, that probe would repeat its timeout on every Site Health load without ever learning anything. perflocale/site_health/probe_export_exposure turns the measurement off. It does not turn the advice off — the check still tells you to add the rule, because a filter should never be able to make a real exposure look green.
Error logs
Keep PHP error logs out of the web root and off systems with a wider audience than your administrators. PerfLocale deliberately never writes an export path, filename or token to a log — it logs a job UUID and a truncated hash instead — but other plugins are not always as careful.
About bounties
PerfLocale is a free, open-source plugin without a formal bug-bounty program at this time. We take every report seriously and credit researchers in published advisories, but we're not able to pay for reports. If a paid program matters to you, consider submitting eligible issues through Wordfence's bug-bounty program, which covers many popular WordPress plugins (eligibility depends on their current scope rules).
Published advisories
Security fixes are listed in the changelog alongside every other change, and anything that materially affects a running site is summarised here as well, with its affected and fixed versions. No issue has needed a CVE to date; if one does, the identifier will be listed with it.
1.0.1 — 5 September 2026
1.0.1 fixed several issues found by internal review. None was publicly disclosed and none is known to have been exploited. The most significant:
- Privilege escalation. A role holding the plugin’s Translator capability plus edit rights could publish, privatise or trash any post it could edit, because status changes were gated on the edit capability alone. Status changes are now mapped to the target post type’s own capabilities.
- Content destruction. The same endpoint accepted WordPress’s internal post statuses. Setting a post to
auto-drafthands it to WordPress’s own routine that permanently deletes abandoned drafts, so a role explicitly denied delete rights could still cause deletion. Internal statuses are now refused. - Information disclosure. Translated Contact Form 7 forms rendered the form’s stored configuration — recipient addresses, mail templates and headers — into the public page. Translated forms now read Contact Form 7’s own form property.
- Guessable export URLs. Export filenames carried roughly six characters of entropy in a web-served directory. They now carry 32, exports are published atomically, and the path is withheld from callers without the import/export capability.
- Quota and policy bypasses. Machine translation requested through the Abilities integration skipped the per-user and site-wide rate limits, and the AI Client provider bypassed WordPress’s
wp_supports_ai()andwp_ai_client_prevent_promptpolicy layer. Both now go through the shared checks.
Affected: 1.0.0. Fixed in: 1.0.1. Updating is recommended for every site.