Skip to content
All systems operational Knowledge base Panel

Security · WordPress

WordPress API Keys: Why wp-config.php Is Still Your Safest Bet — and What the 7.2 Secrets API Could Change

Where to safely store API keys in WordPress: the limits of wp-config.php and what the proposed 7.2 Secrets API would change.

Redação Amicatek6 min read

Anyone who manages WordPress sites has probably opened wp-config.php at some point to drop in an API credential — a Stripe key, an SMTP password, an OpenAI token, a webhook secret. It’s the most common approach, but also one of the most misunderstood: plenty of developers treat constants defined there as “secure enough” without knowing exactly why — or where that assumption breaks down.

With AI agents and MCP-based integrations increasingly calling APIs from inside WordPress installs — something we covered in this article — the number of credentials living on a typical site keeps growing. It’s worth being precise about where they should, and shouldn’t, live.

The risk: most plugins store credentials in plain text

The most common way a plugin stores a credential is as an option in the database, sitting right next to mundane settings like the site tagline. Stripe keys, SMTP passwords, Google tokens, OpenAI keys, webhook signing secrets — all of it often ends up in plain text in the wp_options table.

That exposure has real consequences. These credentials propagate into:

  • Database backups, which are frequently less protected than the production site itself;
  • Staging clones, spun up without much thought about what’s being copied along with the content;
  • Support tickets, when someone exports the options table to debug an issue;
  • Migration dumps, created when moving to a new host.

Every plugin still handles this its own way. Site Kit, WooCommerce, and dozens of others each implement their own encryption layer — when they implement one at all — which multiplies the audit surface and makes incident response inconsistent: every leak requires understanding that specific plugin’s logic from scratch.

Why wp-config.php works better — but isn’t a complete answer

Defining a credential as a constant in wp-config.php solves the most obvious problem: the secret leaves the wp_options table and is no longer exposed through the REST API, the admin screens, or a routine database dump.

// wp-config.php
define( 'OPENAI_API_KEY', 'sk-...' );
define( 'STRIPE_SECRET_KEY', 'sk_live_...' );

And in plugin or theme code:

if ( defined( 'OPENAI_API_KEY' ) ) {
    $client = new OpenAI_Client( OPENAI_API_KEY );
}

Why this isn’t “solved”

wp-config.php reduces the risk, but it carries three limitations agencies tend to forget:

  1. It still travels with the filesystem. If the server is compromised, a backup includes the site root, or a developer accidentally commits the file, the key goes with it. It’s not unusual to find an entire wp-config.php sitting in the Git history of a private repo — and removing the file in a new commit doesn’t scrub it from history.
  2. There’s no rotation or versioning. Rotating a compromised key means editing the file by hand, with no audit trail of when it happened or who had access to the previous value.
  3. It isn’t encryption — it’s relocation. The key is still plain text; it just changed address. Anyone with filesystem read access sees it exactly as they would an option.

Baseline hygiene for wp-config.php

  • Keep wp-config.php out of version control (.gitignore) whenever possible, or move secrets into a separate secrets.php loaded via require, versioned separately with restricted permissions.
  • Set file permissions to 640 or tighter, so only the PHP-FPM user can read it.
  • Never reuse the same key across production and staging — a poorly secured test environment shouldn’t be able to burn through production’s API budget.

Environment variables: the alternative on managed hosting

On hosts that support real environment variables (not a plugin simulating them), this tends to be the cleanest option for technical teams:

// wp-config.php
define( 'OPENAI_API_KEY', getenv( 'OPENAI_API_KEY' ) );

The key never touches the repository or the site’s filesystem — it’s set in the host’s dashboard, in docker-compose.yml, or as an orchestrator secret (Kubernetes, ECS). That solves the Git problem, but not rotation or an audit trail: it’s still a static value someone has to swap by hand when it leaks.

Teams running a local .env file (via vlucas/phpdotenv, for instance) should treat it with the same care as wp-config.php: kept out of Git, tightly permissioned, never committed “just this once to test.”

What the proposed WordPress 7.2 Secrets API could change

In August, a formal proposal went up to bring a native Secrets API into core, with a feature plugin expected to be ready before WordPress 7.2’s Beta 1, scheduled for October 20–22, 2026. The proposal directly targets the three gaps in wp-config.php:

  • Mandatory encryption at rest, built on libsodium, with per-secret data keys wrapped by a master key — not optional, not something you can switch off.
  • A standardized API: wp_set_secret(), wp_get_secret(), wp_delete_secret(), and wp_import_option_as_secret() (for migrating keys currently stored as options), returning a WP_Secret object with a reveal() method — making every credential access point greppable for review.
  • Two-slot version rotation (current and previous), letting a key be rotated without breaking integrations still relying on the previous value during a short transition window.
  • No filters on the read path, closing off the possibility of a rogue plugin intercepting a plaintext key mid-request.

Worth flagging: this is still a proposal under active discussion, not a confirmed feature. The admin UI for managing secrets was deliberately left out of 7.2 and is expected to land in 7.3 at the earliest, once real usage patterns emerge. For the December 2026 release, initial access is expected to ship via WP-CLI.

What this means for plugin developers

If the proposal lands roughly as written, plugin code that today looks like:

$key = get_option( 'my_plugin_api_key' );

would become:

$secret = wp_get_secret( 'my-plugin/api-key' );
if ( null !== $secret && ! is_wp_error( $secret ) ) {
    $client = new API_Client( $secret->reveal() );
}

This doesn’t eliminate the need for care — a developer can still log the output of reveal() by mistake — but it replaces dozens of parallel, plugin-specific encryption schemes with a single, auditable, encrypted-by-default chokepoint.

Checklist for agencies and developers

Until the Secrets API ships — and afterward, for plugins that haven’t migrated yet:

  • [ ] Audit installed plugins: which ones store credentials as plain-text options? (check wp_options directly via wp option list --search="*key*" in WP-CLI)
  • [ ] Move critical credentials to wp-config.php or environment variables instead of admin fields that auto-save into the database, whenever that’s an option.
  • [ ] Confirm wp-config.php is excluded from the project’s version control.
  • [ ] Tighten file permissions and review who has SSH/SFTP access to production.
  • [ ] Never reuse production keys in staging or development.
  • [ ] Check backups: confirm whether database dumps include credentials, and if so, who can access them.

If your agency or company manages multiple WordPress sites with AI, payment, or automation integrations, this is exactly the kind of item that slips through a quick audit — and becomes a headline when it does.

Sources

Not sure how many API keys are scattered across the plugins on your WordPress sites? Request a free site assessment from Amicatek and find out what needs attention before it becomes an incident.