Security
How SiteRank AI handles credentials, outbound requests, permissions and your data — including the limits of what it can protect.
SiteRank AI runs inside your WordPress installation and reads a great deal of your site. This page describes what it does with that access, what leaves your server and what does not, and where the protections stop. Where a control has a limit, the limit is stated rather than implied away.
No compliance certification is claimed anywhere on this page. SiteRank AI holds no SOC 2 report, no ISO 27001 certificate and no third-party audit attestation. What follows is a description of how the software behaves, which you can verify by reading it.
Analysis is local
The analysis engine makes no outbound requests. Content scanning, technical SEO auditing, GEO auditing, topic clustering, structured-data inspection and crawler-policy inspection all run inside your install, against your own database, and produce their results there.
That is an architectural property, not a setting. The core product works with no API key configured, so there is no path by which your content could be sent anywhere as part of an audit. Your posts, pages, taxonomies, metadata, internal link graph and topic clusters never leave the server they were computed on.
When an external API is used, and what is sent
There is exactly one outbound data flow: AI visibility monitoring, which is optional and off until you configure it.
When a monitoring run executes, the product sends the prompt text you wrote to the provider you configured, using your own key. Nothing else goes with it. No post content, no URLs, no corpus, no topic model, no site metadata, no WordPress version, no user information. The request body is constructed from the stored prompt row alone, so the boundary is enforced by the code path rather than by a policy someone has to remember.
The provider's response comes back and is analysed locally for mentions and citations. That response is treated as untrusted input: it is never executed, never followed as an instruction, and never rendered as markup. It becomes data presented to a person.
Nothing is proxied through us. Your server talks to your provider directly, and we operate no service that sees your traffic.
Bring your own key
We ship no API keys and resell no API access. You supply a provider credential, it stays on your server, and the provider bills you directly.
Credentials resolve in a fixed precedence, and the first one found wins:
- Environment variable — set in your server or container environment. Never in the database, never in a file inside the web root.
wp-config.phpconstant — defined outside the database, above the document root on a correctly configured host.- Encrypted value in the database — entered in the admin, encrypted at rest with libsodium's authenticated `secretbox`, using a key derived from a dedicated encryption constant (falling back to an existing WordPress auth salt) plus a per-installation salt.
Where an environment variable or a constant supplies the key, the admin screen shows it as configured by the server and read-only. The interface cannot overwrite what the server set.
The honest threat model for the encrypted tier
Encrypting a credential in the database does not make it safe from everything, and claiming otherwise would be the kind of statement this product exists to avoid.
If the derivation secret lives in wp-config.php and the ciphertext lives in the database, an attacker who holds both holds the key. Encryption at rest defends against database-only exposure: SQL injection that reads a table, a leaked or stolen database backup, a rogue database reader, a shared-hosting neighbour with database access. It does not defend against an attacker with filesystem access to wp-config.php, an administrator-level account compromise, or code execution on the server. The plugin's own interface says exactly this next to the field.
If your threat model includes filesystem compromise, use an environment variable, which keeps the credential out of both the database and the web root.
Credentials never reach the browser, or a log
A stored key is never returned to the browser under any circumstance — not in a REST response, not in localised script data, not in a data attribute, not in a bundle, and not to an administrator who asks for it. The admin receives a masked hint and a label saying where the credential came from, and can replace or remove it. There is no path that reads a key back out for display.
A single redaction component scrubs every log line, exception message, stored raw provider payload and diagnostics export, both by pattern and by registered value, so a credential cannot be serialised into a debug dump or a support bundle.
SSRF protection on user-supplied URLs
The plugin fetches URLs you supply — your own robots.txt, competitor sites you register as tracked sites, pages you ask it to check. A URL supplied by a user, a post, or a model is a server-side request forgery risk, and every outbound fetch passes through one guard before a connection is opened.
The guard applies, in order:
- Scheme allowlist. Only
httpandhttps. Nofile,gopher,ftpor anything else. - DNS resolution before connecting, so the decision is made on the address that will actually be contacted rather than on how the hostname looks.
- Address rejection for loopback, private ranges, link-local addresses, unique-local IPv6, and cloud instance metadata endpoints — the addresses that turn a fetch into a read of your internal network or your hosting credentials.
- Re-validation on every redirect hop. A permitted host redirecting to an internal address is the standard bypass, and each hop is checked as if it were the original request.
- Bounded time and bounded response size, with an explicit redirect limit, so a slow or enormous response cannot exhaust the request.
Your own site's host is exempt from the private-range check only — fetching your own robots.txt on a local or internal hostname is not SSRF — and from nothing else.
We never fetch a URL because a model asked us to.
Permissions on every route
Every REST route in the plugin names a specific capability in its permission callback. There is no route that permits everyone; the plugin's REST surface contains no __return_true permission callback at all.
Authorisation uses five purpose-built capabilities rather than manage_options, covering viewing, managing settings, running scans, managing integrations and managing visibility. Administrators receive all five when the plugin is activated. Splitting them means an SEO specialist or editor can later be granted only what they need, without being handed what amounts to site ownership.
Every state-changing admin form and action is nonce-protected, and the nonce check is in addition to the capability check, never instead of it.
Beyond that: input is validated and sanitised at the boundary, output is escaped in its rendering context, and every database query with an interpolated value is prepared. Table and column names cannot be parameterised in SQL, so they come from a fixed allowlist, including the columns permitted in an ORDER BY. Crawled HTML and third-party API payloads are handled with the same distrust as model output.
Data retention and deletion
All data the plugin produces lives in your own WordPress database, in its own prefixed tables. It is not replicated anywhere.
- Observations are retained with their full provenance so that history remains verifiable, and retention is under your control in settings.
- Raw provider payloads are stored only if you opt in, are redacted before storage, and are bounded by size and retention period.
- Deactivating the plugin unschedules its jobs and clears runtime state, and destroys nothing.
- Uninstalling preserves your data by default. Dropping the plugin's tables, options and capabilities on removal is an explicit opt-in setting.
- Credentials are always removed on uninstall, whichever retention choice you made.
Reporting a vulnerability
If you find a security defect, report it privately and give us a reasonable period to fix it before disclosing. Include the version, the affected route or component, and the steps to reproduce. The reporting address is on the contact page.
Frequently asked questions
If someone dumps my database, do they have my API key?
Not from the database alone, if you used the encrypted tier: the ciphertext is there and the derivation secret is not. That is precisely the boundary encryption at rest buys you — SQL injection that reads a table, a stolen or leaked backup, a rogue database reader. An attacker who can also read wp-config.php, or who holds an administrator account or code execution on the server, has everything needed regardless. If filesystem compromise is inside your threat model, use an environment variable so the credential is in neither the database nor the web root.
Has any of this been audited by a third party?
No. There is no SOC 2 report, no ISO 27001 certificate and no external audit attestation, and none is claimed anywhere on this page. What is offered instead is a description specific enough to check against the software: the plugin runs as readable PHP inside your own install, so each control described here can be verified by reading the code that implements it rather than taken on trust.
Can I let an editor run scans without making them an administrator?
Yes — that is what the five purpose-built capabilities exist for. Viewing, managing settings, running scans, managing integrations and managing visibility are separate grants, so someone can be given the ability to start a scan without being given the ability to configure a provider credential or spend money on observations. Administrators receive all five at activation; assigning any of them to another role is done through your own role management. The two capabilities that can incur provider cost are deliberately separable from the rest.
What happens to my credential if I remove the plugin?
It is deleted, whichever retention choice you made. Uninstalling preserves your analysis data by default and dropping the plugin's tables, options and capabilities is an explicit opt-in, but the credential is removed either way and is not part of that decision. If the key came from an environment variable or a wp-config.php constant it was never in the database to begin with, so removing it there is your server's business rather than the plugin's. What the retained data consists of is described on the privacy page.