# How to Handle Sensitive Data and Secrets in Claude Plugins

> Learn how to securely handle sensitive data and secrets in Claude plugins. Utilize the built-in secret store for environment variables and avoid hardcoding credentials.

- Repository: [Anthropic/claude-plugins-community](https://github.com/anthropics/claude-plugins-community)
- Tags: best-practices
- Published: 2026-09-13

---

**Claude plugins provide a built-in secret store that injects credentials via environment variables, allowing you to reference sensitive data with `CLAUDE_SECRET_<NAME>` without hardcoding values in your source code.**

The `anthropics/claude-plugins-community` repository implements a secure-by-default pattern for managing API keys, passwords, and tokens. By declaring secrets in your plugin manifest and accessing them through runtime-injected environment variables, you ensure sensitive data never appears in logs or source control.

## Declare Secrets in the Plugin Manifest

Every Claude plugin defines its interface through a manifest file—typically [`SKILL.md`](https://github.com/anthropics/claude-plugins-community/blob/main/SKILL.md) or [`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/plugin.json). To mark a field as sensitive, include the `secret: true` flag or use naming conventions that include `secret`, `private`, `signing`, or `passphrase`.

In [`tres-finance-plugin/skills/tres-wallets-upload/SKILL.md`](https://github.com/anthropics/claude-plugins-community/blob/main/tres-finance-plugin/skills/tres-wallets-upload/SKILL.md), the documentation explicitly instructs users to protect credentials:

> "Please provide these values. Keep API secrets private — do not share them in public channels."

This instruction appears at line 347, demonstrating the repository's standard for user-facing secret documentation【[SKILL.md line 347](https://github.com/anthropics/claude-plugins-community/blob/main/tres-finance-plugin/skills/tres-wallets-upload/SKILL.md#L347)】.

**Example manifest declaration:**

```yaml
fields:
  - name: api_key
    type: string
    description: "Your API key for Example Service"
    secret: true

```

When users configure your plugin through Claude's UI, fields marked as secrets render as masked inputs, preventing shoulder-surfing and clipboard leaks.

## Access Secrets at Runtime via Environment Variables

The Claude runtime transforms declared secrets into environment variables using the pattern `CLAUDE_SECRET_<NAME>` in uppercase with underscores. Your plugin code must read these variables rather than containing literal values.

**Python implementation:**

```python
import os

def get_api_key():
    """Retrieve API key from injected environment variable."""
    api_key = os.getenv("CLAUDE_SECRET_API_KEY")
    if not api_key:
        raise RuntimeError("API key not configured in Claude Secrets")
    return api_key

def call_external_service():
    headers = {"Authorization": f"Bearer {get_api_key()}"}
    # ... perform authenticated request

```

**JavaScript/Node.js implementation:**

```javascript
function getApiKey() {
  const apiKey = process.env.CLAUDE_SECRET_API_KEY;
  if (!apiKey) {
    throw new Error("Missing CLAUDE_SECRET_API_KEY environment variable");
  }
  return apiKey;
}

async function fetchData() {
  const response = await fetch("https://api.example.com/data", {
    headers: { Authorization: `Bearer ${getApiKey()}` },
  });
  return response.json();
}

```

Never cache secret values in global variables or write them to temporary files. Access `os.getenv()` or `process.env` immediately before use to minimize exposure.

## Prevent Exfiltration with CI Scanning

The repository enforces secret safety through automated policy scanning. The [`.github/actions/scan-plugins/policy/prompt.md`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/policy/prompt.md) file contains detection rules that flag any code attempting to exfiltrate live secrets from system keystores:

> "Flag credential / secret EXFILTRATION specifically. This is distinct from hardcoded secrets — look for code that reads the user's live secrets from a … `secret-tool lookup`, Windows `cmdkey`, `keytar`/`keyring`), `~/.aws/credentials`"

This policy appears at lines 22-23 and blocks pull requests that attempt to access external credential stores【[policy prompt line 22-23](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/policy/prompt.md#L22)】.

The scanning action also validates that secrets declared in manifests are not hardcoded in source files. As shown in [`.github/actions/scan-plugins/README.md`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/README.md) at line 62, the CI pipeline injects the `ANTHROPIC_API_KEY` secret for testing purposes, demonstrating the canonical injection pattern while verifying no plaintext credentials exist in the codebase【[scan-plugins README line 62](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/README.md#L62)】.

## Encrypt Data at Rest (Optional)

For plugins that persist sensitive configuration between sessions, store encrypted `.secenv` files using keys maintained in Claude's secret store. The encryption key itself should be declared as a secret in [`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/plugin.json), ensuring that:

1. At-rest data remains encrypted when the plugin is not running
2. Decryption only occurs when the runtime injects the key via `CLAUDE_SECRET_ENCRYPTION_KEY`
3. No plaintext keys reside in the file system

## Summary

- **Declare secrets explicitly** in [`SKILL.md`](https://github.com/anthropics/claude-plugins-community/blob/main/SKILL.md) or [`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/plugin.json) using the `secret: true` flag or sensitive naming conventions.
- **Access via environment variables** using the `CLAUDE_SECRET_<NAME>` pattern in uppercase; never hardcode credentials in Python, JavaScript, or configuration files.
- **Validate through CI** by ensuring the scan-plugins GitHub Action passes; this blocks exfiltration attempts and hardcoded secrets.
- **Log safely** by never printing secret values to stdout, stderr, or error messages—Claude's runtime masks these values automatically, but your code must avoid manual logging of credential variables.

## Frequently Asked Questions

### How do I declare multiple secrets for one plugin?

Declare each sensitive field as a separate entry in the `fields` array of your [`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/plugin.json) or [`SKILL.md`](https://github.com/anthropics/claude-plugins-community/blob/main/SKILL.md) manifest. Each field with `secret: true` becomes a distinct environment variable prefixed with `CLAUDE_SECRET_`. For example, `fields: [{name: "stripe_key", secret: true}, {name: "webhook_secret", secret: true}]` injects `CLAUDE_SECRET_STRIPE_KEY` and `CLAUDE_SECRET_WEBHOOK_SECRET`.

### What happens if a secret is not configured?

If a user has not provided a value for a declared secret, the corresponding `CLAUDE_SECRET_<NAME>` environment variable will be unset or empty. Your code should validate this with `os.getenv()` or `process.env` checks and raise clear runtime errors indicating which credential is missing, as shown in the Python and JavaScript examples above.

### Can I rotate secrets without redeploying the plugin?

Yes. Because secrets are stored in Claude's built-in secret store and injected at runtime, updating a secret value in the Claude UI immediately affects subsequent plugin invocations. You do not need to modify source code or restart the plugin server—the new value propagates through the environment variable on the next execution.

### How does the CI scanner distinguish between hardcoded secrets and legitimate secret access?

The policy in [`.github/actions/scan-plugins/policy/prompt.md`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/policy/prompt.md) specifically looks for exfiltration patterns—code that reads from system keystores like `secret-tool`, Windows Credential Manager, or `~/.aws/credentials`. Legitimate plugins only access `CLAUDE_SECRET_*` environment variables injected by the runtime. Hardcoded literals matching high-entropy patterns (API key formats) are flagged separately by the same scanning action.