# Security Considerations for OpenAI Plugins: Defense-in-Depth for AI Skill Integrations

> Explore security considerations for OpenAI plugins. Implement defense-in-depth with HTTPS TLS 1.2+, PKCE OAuth, server-side tokens, and webhook validation to prevent attacks.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: security-best-practices
- Published: 2026-06-26

---

**OpenAI plugins require a defense-in-depth security posture that enforces HTTPS with TLS 1.2+, implements PKCE-based OAuth flows, stores all tokens server-side, and validates webhook signatures to protect against CSRF, token leakage, and man-in-the-middle attacks.**

OpenAI plugins are independent code bundles that run across diverse environments—from cloud functions to local developer hosts—and expose skill definitions via JSON manifests. Because these plugins can be invoked by any ChatGPT session, they must adopt strict security controls covering transport encryption, authentication, and data protection. Implementing the correct security considerations for OpenAI plugins ensures compliance with marketplace requirements and safeguards end-user data against common attack vectors.

## Transport-Layer Security and HTTPS Enforcement

All external endpoints must reject plain HTTP traffic and enforce TLS 1.2 or higher. According to the Zoom security documentation in [`plugins/zoom/skills/zoom-apps-sdk/concepts/security.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/concepts/security.md), plugins must redirect HTTP requests to HTTPS and implement OWASP-recommended security headers.

### TLS Requirements and Certificate Management

Use valid, non-self-signed certificates for production environments. For local development, tools like `ngrok` automatically supply trusted certificates. The source code explicitly prohibits downgrading to plain HTTP connections.

### OWASP Security Headers

Implement strict transport and content security policies to prevent clickjacking and MIME-type sniffing. The following headers are required:

- `Strict-Transport-Security`: Enforce HTTPS for one year
- `X-Content-Type-Options: nosniff`: Prevent MIME-type sniffing
- `Content-Security-Policy`: Restrict framing to the hosting platform (e.g., `frame-ancestors 'self' zoom.us *.zoom.us`)
- `Referrer-Policy: same-origin`: Limit referrer information leakage
- `X-Frame-Options`: Control iframe embedding

```javascript
app.use((req, res, next) => {
  res.setHeader('Strict-Transport-Security', 'max-age=31536000');
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('Content-Security-Policy',
    "frame-ancestors 'self' zoom.us *.zoom.us");
  res.setHeader('Referrer-Policy', 'same-origin');
  next();
});

```

## Authentication and Authorization Controls

Plugin authentication must use industry-standard OAuth 2.0 flows with additional protections against interception and replay attacks.

### OAuth PKCE Implementation

Use **PKCE** (Proof Key for Code Exchange) for all public clients to prevent authorization code interception attacks. Never expose client secrets in frontend code or browser bundles.

The implementation generates a random verifier and challenge:

```javascript
const crypto = require('crypto');

const verifier = crypto.randomBytes(32).toString('hex');
const challenge = crypto.createHash('sha256')
  .update(verifier)
  .digest('base64url');

// Store verifier server-side only
req.session.codeVerifier = verifier;

```

### CSRF Protection via State Parameter

Generate a cryptographically random `state` token before redirecting to the OAuth provider and validate it upon callback. This prevents cross-site request forgery attacks where malicious sites initiate OAuth flows without user consent.

```javascript
// Before OAuth redirect
const state = crypto.randomBytes(16).toString('hex');
req.session.oauthState = state;

// Callback validation
app.get('/auth', (req, res) => {
  if (req.query.state !== req.session.oauthState) {
    return res.status(403).send('Invalid state – possible CSRF');
  }
  // Continue token exchange...
});

```

### Webhook Signature Verification

Verify signatures on incoming webhook requests before processing payloads. Platforms like Zoom and Twilio provide signature validation mechanisms in [`plugins/zoom/skills/rest-api/references/authentication.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/rest-api/references/authentication.md) and [`plugins/twilio-developer-kit/skills/twilio-security-hardening/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/twilio-developer-kit/skills/twilio-security-hardening/SKILL.md). Always reject webhooks with invalid or missing signatures.

## Data Protection and Token Storage

Sensitive credentials must never transit through or persist in client-side environments.

### Server-Side Token Persistence

Persist access and refresh tokens exclusively on the server side using encrypted databases or cache systems like Redis. According to [`plugins/zoom/skills/zoom-apps-sdk/concepts/security.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/concepts/security.md), storing tokens in `localStorage`, `sessionStorage`, or browser cookies exposes them to XSS attacks.

```javascript
const Redis = require('ioredis');
const redis = new Redis(process.env.REDIS_URL);

async function storeTokens(userId, tokens) {
  await redis.set(`zoom:tokens:${userId}`, JSON.stringify(tokens), 'EX', tokens.expires_in);
}

```

### Secure Cookie Configuration for Cross-Origin Embedding

When cookies are required for session management, set `SameSite=None` and `Secure` because plugins run inside cross-origin embedded frames. Use `HttpOnly` flags to prevent JavaScript access.

```javascript
app.use(require('cookie-session')({
  name: 'session',
  keys: [process.env.SESSION_SECRET],
  maxAge: 24 * 60 * 60 * 1000,
  sameSite: 'none',
  secure: true
}));

```

## Runtime Security and Dependency Management

### Automated Security Scanning

Integrate static analysis tools into CI/CD pipelines. The `codex-security` skill in [`plugins/codex-security/scripts/validate_report_format.py`](https://github.com/openai/plugins/blob/main/plugins/codex-security/scripts/validate_report_format.py) provides automated security checks for pull requests, validating that secrets are not exposed and dependencies are current.

### Dependency Updates and Secrets Management

Regularly update third-party libraries to include security patches (e.g., React 19.2+, Node.js ≥ 18). Store all API keys, client IDs, and secrets in environment variables (`process.env.*`) and verify that build tools like Vercel flag environment variables exposed in client bundles.

## Platform-Specific Security Implementations

Different hosting platforms provide specialized security features:

- **Zoom**: Requires OWASP headers, CSP, PKCE, and webhook signature verification as documented in [`plugins/zoom/skills/zoom-apps-sdk/concepts/security.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/concepts/security.md)
- **Twilio**: Implements credential hardening, signed webhook events, and IAM policies for HIPAA compliance per [`plugins/twilio-developer-kit/skills/twilio-security-hardening/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/twilio-developer-kit/skills/twilio-security-hardening/SKILL.md)
- **Vercel**: Provides WAF capabilities, rate limiting, and DDoS protection through the `vercel-firewall` skill in [`plugins/vercel/skills/vercel-firewall/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/vercel/skills/vercel-firewall/SKILL.md)
- **Supabase**: Offers database-level access control and security indexing via [`plugins/supabase/skills/supabase/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/supabase/skills/supabase/SKILL.md)

## Summary

- **Enforce TLS 1.2+** and implement OWASP security headers including `Strict-Transport-Security` and `Content-Security-Policy`
- **Use PKCE** for OAuth flows and validate `state` parameters to prevent CSRF attacks
- **Store tokens server-side** only (Redis, encrypted databases) and never in browser storage
- **Configure cookies** with `SameSite=None; Secure` for cross-origin embedding contexts
- **Verify webhook signatures** before processing incoming payloads
- **Run automated security scans** using tools like `codex-security` and keep dependencies updated

## Frequently Asked Questions

### What is PKCE and why is it required for OpenAI plugins?

**PKCE** (Proof Key for Code Exchange) is an extension to the OAuth 2.0 authorization code flow that prevents authorization code interception attacks. Since OpenAI plugins often run as public clients where client secrets cannot be securely stored, PKCE provides a cryptographic verifier that ensures the entity exchanging the authorization code is the same one that initiated the request. This is implemented in [`plugins/zoom/skills/zoom-apps-sdk/concepts/security.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/concepts/security.md) as a mandatory control for public OAuth clients.

### How should I store access tokens for my OpenAI plugin?

Access and refresh tokens must be stored exclusively on the server side using encrypted databases, Redis, or secure cloud storage solutions. Never store tokens in browser `localStorage`, `sessionStorage`, or client-side cookies where they are vulnerable to XSS attacks. The Zoom security documentation in [`plugins/zoom/skills/zoom-apps-sdk/concepts/security.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/concepts/security.md) provides a token storage matrix that mandates server-side persistence.

### Why do OpenAI plugins require `SameSite=None` cookies?

OpenAI plugins run inside embedded frames that are cross-origin relative to the hosting ChatGPT interface. Standard `SameSite=Strict` or `Lax` cookies would be blocked in this cross-origin context. Setting `SameSite=None` with the `Secure` flag allows the browser to send cookies while maintaining encryption in transit. This configuration is specifically documented in the cookie security section of [`plugins/zoom/skills/zoom-apps-sdk/concepts/security.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/zoom-apps-sdk/concepts/security.md).

### How do I validate webhook signatures in OpenAI plugins?

Webhook validation involves computing an HMAC signature using the webhook payload and a secret key shared with the service provider (e.g., Zoom, Twilio), then comparing it against the signature sent in the request headers. If the signatures do not match, the request must be rejected immediately. Implementation details are available in [`plugins/zoom/skills/rest-api/references/authentication.md`](https://github.com/openai/plugins/blob/main/plugins/zoom/skills/rest-api/references/authentication.md) for Zoom webhooks and [`plugins/twilio-developer-kit/skills/twilio-security-hardening/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/twilio-developer-kit/skills/twilio-security-hardening/SKILL.md) for Twilio events.