AID-H-028.002: Client Credential Secure Storage & Lifecycle Management

Version 1.20261015 · Actionable sub-technique

Ensure that credentials used by the MCP client to authenticate with remote servers (API keys, OAuth tokens, refresh tokens, client certificates, session tokens) are stored using platform-native secure storage mechanisms such as OS keychains, encrypted secret stores, or hardware-backed keystores rather than plaintext configuration files. This sub-technique also covers credential lifecycle management: rotation, expiry enforcement, revocation propagation, logout cleanup, and client deauthorization. This directly addresses one of the most common weaknesses in current MCP client implementations: credentials stored in readable local JSON or text configuration files.

Pillars: infra, app

Lifecycle: building, operation

Scope boundary

Owns secure local storage, rotation, expiry, revocation propagation, logout cleanup, and deauthorization of credentials held by an MCP or tool client. It does not define server authentication policy or revoke the upstream credential authority's objects.

AID-H-004.002: AID-H-028.002 protects credentials in the MCP client and their local lifecycle; AID-H-004.002 defines service and API authentication controls across the broader system. Secure storage does not determine whether the remote service accepts the credential correctly.

AID-E-001: AID-H-028.002 propagates revocation and cleans local client copies; AID-E-001 owns incident-driven revocation of compromised credentials, sessions, principals, and grants at their authorities. Deleting a local token copy does not invalidate an already issued credential.

Implementation guidance

AID-H-028.002-G001

Store client-held credentials in the platform-native keychain or a managed encrypted secret store, never in plaintext configuration files.
Concept:

Keep only a reference to the credential in config. Store the real secret in the OS keychain or secret manager. If the platform has no keychain support, use an encrypted file and lock down file permissions.

Example Python keyring usage
import keyring

SERVICE = "mcp-client"
ACCOUNT = "finance-mcp-api-key"

# Store secret once
keyring.set_password(SERVICE, ACCOUNT, "sk_live_xxx")

# Read secret later
api_key = keyring.get_password(SERVICE, ACCOUNT)
if not api_key:
    raise RuntimeError("Missing MCP credential in keychain")
Example config that stores only a reference
{
  "servers": [
    {
      "name": "finance-mcp",
      "url": "https://mcp.finance.internal",
      "auth": {
        "type": "api_key",
        "keychain_ref": "mcp-client:finance-mcp-api-key"
      }
    }
  ]
}

Operational notes: Add a startup audit that scans known config paths for obvious secret patterns and fails if plaintext credentials are found. Allow a SOPS-encrypted fallback only where keychain APIs are not available.

Production implementation

At credential creation and retrieval, store only through the platform keychain or managed secret API under the exact client identity and server scope, deny plaintext fallback/export, and verify effective ACL and hardware-backed status when policy requires it.

Independent verification

A separately credentialed verifier independently reads back or replays keychain/secret-store metadata, effective ACL, process access and absence from config, logs, backups and crash artifacts using authorized and unauthorized identities.

AID-H-028.002-G002

Enforce credential TTLs, rotation, and expiry-based invalidation for long-lived client tokens and refresh flows.
Concept:

Do not treat client tokens as permanent. Track expiry and refresh before expiry. If refresh fails or the token is revoked, block further use.

Example token metadata file
{
  "token_ref": "mcp-client:finance-oauth-access-token",
  "expires_at": "2026-03-20T18:00:00Z",
  "refresh_ref": "mcp-client:finance-oauth-refresh-token",
  "server": "finance-mcp"
}
Example expiry check
from datetime import datetime, timezone

def token_is_stale(expires_at_iso: str, safety_window_seconds: int = 300) -> bool:
    expires_at = datetime.fromisoformat(expires_at_iso.replace("Z", "+00:00"))
    now = datetime.now(timezone.utc)
    return (expires_at - now).total_seconds() <= safety_window_seconds

Operational notes: Log every refresh, rotation, and revocation event with server, credential_type, and result. Where possible, use short-lived access tokens and keep refresh tokens in a stronger store than ordinary app config.

Production implementation

At issuance, refresh and request dispatch, enforce signed policy expiry, rotation generation, audience/resource and revocation state; atomically replace old material and deny stale, superseded or unverifiable credentials.

Independent verification

A separately credentialed verifier independently reads back or replays issuer records, local credential generation, effective token claims and dispatch decisions across expiry, rotation race, clock-boundary, replay and revocation fixtures.

AID-H-028.002-G003

On logout, deauthorization, or uninstall, remove locally accessible credentials and revoke server-side tokens where supported.
Concept:

Do not promise impossible secure deletion semantics on every OS and filesystem. Instead, remove secrets through the native secret-store API, delete any local references, revoke tokens server-side, and purge accessible client-managed session state.

Example Python cleanup flow
import keyring

SERVICE = "mcp-client"

def cleanup(server_name: str, account_refs: list[str]):
    for ref in account_refs:
        keyring.delete_password(SERVICE, ref)
    # Then call remote revocation endpoint if available.
    # Finally delete client-local session files and cached auth metadata.

Operational notes: Maintain a manifest of secret references per server. At uninstall time, iterate through that manifest, remove local secrets, delete cached auth metadata, revoke remote tokens if the server supports revocation, and write a final audit record that the cleanup workflow finished successfully or failed.

Production implementation

At lifecycle teardown, enumerate all locally reachable credential generations, delete them through the native store, invoke issuer revocation where supported, invalidate refresh state and prove subsequent use is denied; unresolved revocation blocks a clean completion state.

Independent verification

A separately credentialed verifier independently reads back or replays the pre/post local inventory, issuer revocation status and fresh authentication probes for every affected credential and device.

Open-source tools

Source-available / open-weight tools

Commercial / hosted tools

Threat mappings

MITRE ATLAS

MAESTRO

OWASP LLM Top 10 2026

OWASP ML Top 10 2023

OWASP Top 10 for Agentic Applications 2026

NIST Adversarial Machine Learning 2025

Cisco Integrated AI Security and Safety Framework

Google Secure AI Framework 2.0 - Risks

Databricks AI Security Framework 3.0

AID-H-028.002: Client Credential Secure Storage & Lifecycle Management | AIDEFEND

Loading interactive view…

A Practical Knowledge Base for AI Security Defenses

Version