---
title: "Security - Responsible Disclosure Policy - PerfLocale"
description: "How to responsibly report a security issue in PerfLocale. Contact security@perflocale.com. Our response-time commitments and published advisories."
canonical: "https://perflocale.com/security/"
source: "https://perflocale.com/security/"
format: "markdown"
---
# 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:** [security@perflocale.com](mailto:security@perflocale.com)

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](https://hackerone.com/wordpress)).
-   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:

```nginx
location ~* /wp-content/uploads/perflocale/exports/ {
	deny all;
	return 404;
}
```

```
@perflocale_exports path /wp-content/uploads/perflocale/exports/*
respond @perflocale_exports 404
```

**You 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`](https://perflocale.com/docs/hooks/#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](https://www.wordfence.com/threat-intel/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](https://perflocale.com/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-draft` hands 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()` and `wp_ai_client_prevent_prompt` policy layer. Both now go through the shared checks.

**Affected:** 1.0.0. **Fixed in:** 1.0.1. Updating is recommended for every site.

[Email security@perflocale.com](mailto:security@perflocale.com)
