PHPackages                             jazzsequence/ai-connector-secure-layer - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. jazzsequence/ai-connector-secure-layer

ActiveWordpress-plugin[Security](/categories/security)

jazzsequence/ai-connector-secure-layer
======================================

Keeps LLM API keys out of the WordPress database. Fetches keys from Pantheon Secrets or environment variables on-demand at the moment an LLM request fires — never stored in wp\_options, never pre-loaded as a PHP constant.

1.0.0(1mo ago)02.1k↑2837%[1 PRs](https://github.com/jazzsequence/ai-connector-secure-layer/pulls)MITPHPPHP &gt;=8.2CI passing

Since May 27Pushed 1mo agoCompare

[ Source](https://github.com/jazzsequence/ai-connector-secure-layer)[ Packagist](https://packagist.org/packages/jazzsequence/ai-connector-secure-layer)[ RSS](/packages/jazzsequence-ai-connector-secure-layer/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (5)Versions (3)Used By (0)

AI Connector Secure Layer
=========================

[](#ai-connector-secure-layer)

[![WordPress 7.0+](https://camo.githubusercontent.com/4faca2ac0febb7370f5541b85e0dc72d36130d729ac57ee096f95178fbf03c7d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f576f726450726573732d372e302532422d3030373361613f6c6f676f3d776f72647072657373266c6f676f436f6c6f723d7768697465)](https://camo.githubusercontent.com/4faca2ac0febb7370f5541b85e0dc72d36130d729ac57ee096f95178fbf03c7d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f576f726450726573732d372e302532422d3030373361613f6c6f676f3d776f72647072657373266c6f676f436f6c6f723d7768697465)[![GitHub Release](https://camo.githubusercontent.com/cf7af32d41dba3a04a2ccbeed63f41348dd3e3b02815ab3b2ce7ffa14454d2c3/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6a617a7a73657175656e63652f61692d636f6e6e6563746f722d7365637572652d6c61796572)](https://camo.githubusercontent.com/cf7af32d41dba3a04a2ccbeed63f41348dd3e3b02815ab3b2ce7ffa14454d2c3/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f6a617a7a73657175656e63652f61692d636f6e6e6563746f722d7365637572652d6c61796572)[![GitHub License](https://camo.githubusercontent.com/0a109d236a71b824b66645dbf492b9a4dd17aa3febf0700b627d7ecf678f2e40/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a617a7a73657175656e63652f61692d636f6e6e6563746f722d7365637572652d6c61796572)](https://camo.githubusercontent.com/0a109d236a71b824b66645dbf492b9a4dd17aa3febf0700b627d7ecf678f2e40/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a617a7a73657175656e63652f61692d636f6e6e6563746f722d7365637572652d6c61796572)[![CI](https://github.com/jazzsequence/ai-connector-secure-layer/actions/workflows/ci.yml/badge.svg)](https://github.com/jazzsequence/ai-connector-secure-layer/actions/workflows/ci.yml)

Keeps LLM API keys out of the WordPress database. Works with WordPress 7.0 AI Connectors and Pantheon Secrets.

The problem
-----------

[](#the-problem)

WordPress 7.0 AI Connectors store API keys in `wp_options` by default. A database dump, SQL injection, or any plugin vulnerability that exposes the database immediately exposes every API key on the site — with no active session required.

How this plugin works
---------------------

[](#how-this-plugin-works)

Instead of storing keys in the database, the plugin fetches them on-demand from Pantheon Secrets (or environment variables) at the exact moment an LLM HTTP request is made — and only then.

```
init:15  wp_connectors_init fires
           → plugin registers pre_update_option hooks to block DB writes for all AI connector options

init:20  _wp_connectors_pass_default_keys_to_ai_client() runs
           → finds empty DB options (writes blocked) → skips all providers

init:21  plugin injects Lazy_Auth into the AI client registry for each configured provider
           → Lazy_Auth stores only the provider ID, not the key

LLM request fires (e.g. Gutenberg AI feature)
           → model calls getApiKey() on Lazy_Auth
           → pantheon_get_secret() or getenv() is called HERE
           → real key injected into request headers
           → key exists in PHP memory only for this call

```

**What this protects against:**

- Database dump — no key is ever written to `wp_options`
- Broad PHP execution — no PHP constant is defined; the key is not in any global
- Idle requests — key only exists in memory during an active LLM API call

**What this does not protect against:**

- An attacker with PHP code execution who knows to call `pantheon_get_secret()` directly can still retrieve the key. No server-side architecture can prevent this: the key must be available to PHP when the LLM call is made.

See the detailed threat model notes in the [Security Model](#security-model) section.

Requirements
------------

[](#requirements)

- WordPress 7.0+
- PHP 8.1+
- A WordPress AI provider plugin (`ai-provider-for-anthropic`, `ai-provider-for-google`, etc.)
- Pantheon Secrets or environment variables for key storage

Installation
------------

[](#installation)

```
composer require jazzsequence/ai-connector-secure-layer
```

Activate the plugin, then install an AI provider plugin. **Do not enter API keys in Settings → Connectors** — use Terminus instead.

Configuration (Pantheon)
------------------------

[](#configuration-pantheon)

For each provider you want to connect, set the key via Terminus:

```
terminus secret:site:set your-site-name anthropic_api_key sk-ant-YOUR_KEY --type=runtime --scope=web,user
terminus secret:site:set your-site-name google_api_key YOUR_GOOGLE_KEY --type=runtime --scope=web,user
```

**Secret name convention:** `{provider_id}_api_key`

Provider IDSecret name`anthropic``anthropic_api_key``google``google_api_key``openai``openai_api_key`Once set, reload Settings → Connectors — the provider shows "This API key is configured as a constant." with a green Connected badge. No key entry form is shown.

Configuration (non-Pantheon)
----------------------------

[](#configuration-non-pantheon)

Set an environment variable at the server level:

```
ANTHROPIC_API_KEY=sk-ant-YOUR_KEY
GOOGLE_API_KEY=YOUR_GOOGLE_KEY
```

**Convention:** `strtoupper({provider_id}) . '_API_KEY'`

User experience
---------------

[](#user-experience)

### Before configuring a key

[](#before-configuring-a-key)

Settings → Connectors shows the provider with a "Set up" button and an admin notice:

> **AI keys managed via Pantheon Secrets**This site manages AI provider API keys through Pantheon Secrets — not through this form. Keys entered here cannot be saved. To connect a provider, run: `terminus secret:site:set your-site anthropic_api_key YOUR_KEY`

### After configuring via Terminus

[](#after-configuring-via-terminus)

The provider shows:

- Read-only field with "This API key is configured as a constant."
- Green "Connected" badge
- No input field — nothing to save

### AI features

[](#ai-features)

WordPress AI features (Gutenberg AI blocks, etc.) work normally once a key is configured. The key is fetched at request time — no restart or cache flush needed.

Security model
--------------

[](#security-model)

**Key is never in:**

- `wp_options` (writes are blocked)
- A PHP constant (`ANTHROPIC_API_KEY` is never defined)
- The AI client registry at init time (lazy auth holds only the provider ID)

**Key is in PHP memory only during:**

- The `getApiKey()` call inside `AnthropicTextGenerationModel::getRequestAuthentication()`
- The subsequent HTTP request to the LLM API

**Remaining attack surface:**

An attacker with arbitrary PHP code execution can still call `pantheon_get_secret('anthropic_api_key')` directly. The key must be available to PHP at request time — this cannot be eliminated at the plugin level for server-side LLM calls. This is meaningfully narrower than the default `wp_options` approach, where DB read access alone is sufficient to retrieve the key.

For more on the threat model and Oliver Sild's analysis that motivated this plugin, see the [WordPress.org readme](readme.txt).

Development
-----------

[](#development)

```
cd web/app/plugins/ai-connector-secure-layer
composer install

# Unit tests (no WordPress required)
composer test

# Integration tests (requires WordPress test suite)
composer test:integration

# Linting
composer lint
```

License
-------

[](#license)

MIT

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance91

Actively maintained with recent releases

Popularity23

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 95% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

58d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/af6c0ce1d250a8a8edc57b4759dabc3d5f7956fc105450bba7fc5d2eb5b74362?d=identicon)[jazzsequence](/maintainers/jazzsequence)

---

Top Contributors

[![jazzsequence](https://avatars.githubusercontent.com/u/991511?v=4)](https://github.com/jazzsequence "jazzsequence (19 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jazzsequence-ai-connector-secure-layer/health.svg)

```
[![Health](https://phpackages.com/badges/jazzsequence-ai-connector-secure-layer/health.svg)](https://phpackages.com/packages/jazzsequence-ai-connector-secure-layer)
```

###  Alternatives

[mews/purifier

Laravel 5/6/7/8/9/10 HtmlPurifier Package

2.0k18.7M144](/packages/mews-purifier)[paragonie/ecc

PHP Elliptic Curve Cryptography library

24820.0k41](/packages/paragonie-ecc)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
