Back to skill

Security audit

Agentlair Vault

Security checks for vulnerabilities and agentic risk

Overview

This skill is a coherent hosted credential vault, but it asks agents to send and persist high-impact API keys with under-disclosed plaintext handling and weak optional encryption guidance.

Review before installing. Use this only if you are comfortable trusting AgentLair as a custodian for the credentials you store there. Prefer least-privileged and revocable provider keys, avoid storing live financial or admin tokens unless necessary, require explicit confirmation before rotate or delete actions, and do not rely on the optional AES-CBC shell example for zero-knowledge storage.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

other

Error
Location
SKILL.md:69
Finding
Plaintext Credentials Disclosed to an External Vault Service<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:69-72`, `SKILL.md:201-204` **Vulnerability Type**: Plaintext credential disclosure to an external service **Risk Level**: Critical ### Vulnerable Code ```bash curl -s -X PUT "https://agentlair.dev/v1/vault/anthropic-key" \ -H "Authorization: Bearer $AGENTLAIR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"ciphertext": "sk-ant-YOUR-KEY-HERE", "metadata": {"label": "Anthropic API key", "service": "anthropic"}}' ``` The example session repeats the same behavior with a Stripe credential: ```bash curl -s -X PUT "https://agentlair.dev/v1/vault/stripe-live" \ -H "Authorization: Bearer $AGENTLAIR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"ciphertext": "sk_live_USER_PROVIDED_KEY", "metadata": {"label": "Stripe live key", "service": "stripe"}}' ``` ### Technical Analysis The default workflow sends user-provided third-party credentials to `https://agentlair.dev` as plaintext JSON protected only by transport-layer TLS. Although the request property is named `ciphertext`, the supplied value is not encrypted before transmission. The documented retrieval response also returns the same secret through both the `ciphertext` and `value` properties, demonstrating that the default storage workflow handles a recoverable plaintext value. Network access is intrinsic to a hosted vault, but granting the external service access to plaintext credentials is not the minimum privilege necessary. Mandatory client-side encryption could permit remote storage without allowing the service operator to recover the underlying credentials. The Skill encourages storage of credentials for high-impact services such as Stripe, Anthropic, OpenAI, and Slack. Consequently, compromise or malicious operation of the vault service could expose credentials spanning financial, communications, and cloud-service accounts. ### Attack Path 1. A user gives the agent a third-party API key or token. 2. The Skill ins ...[truncated 1221 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not upload plaintext credentials to the hosted vault. - Make client-side authenticated encryption mandatory rather than optional. - Use a modern authenticated-encryption construction such as AES-GCM or XChaCha20-Poly1305. - Keep encryption and key-encryption keys outside AgentLair and ensure the remote service cannot recover them. - Obtain explicit, informed user authorization before transmitting each credential to a third-party custodian. - Clearly disclose the service's trust boundary, plaintext-access model, retention behavior, breach implications, and account-recovery risks. - Apply per-secret or per-service authorization instead of allowing one bearer token to retrieve every credential in an account. - Support narrowly scoped, short-lived access tokens and immediate revocation. - Avoid printing secret-bearing responses and ensure command output, shell history, process arguments, and agent transcripts do not retain plaintext values. - Document and independently verify server-side controls, including access logging, encryption at rest, operator access restrictions, tenant isolation, and incident response. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:267
Finding
Unauthenticated AES-CBC and Unsafe Passphrase Handling in Optional Encryption Workflow<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:267-280` **Vulnerability Type**: Insecure client-side encryption guidance **Risk Level**: Medium ### Vulnerable Code ```bash # Encrypt locally before storing SECRET="sk-ant-YOUR-KEY" ENCRYPTED=$(echo -n "$SECRET" | openssl enc -aes-256-cbc -base64 -k "$LOCAL_PASSPHRASE") curl -s -X PUT "https://agentlair.dev/v1/vault/anthropic-key" \ -H "Authorization: Bearer $AGENTLAIR_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"ciphertext\": \"$ENCRYPTED\", \"metadata\": {\"encrypted\": \"aes-256-cbc\", \"label\": \"Anthropic API key\"}}" # Decrypt when fetching CIPHERTEXT=$(curl -s "https://agentlair.dev/v1/vault/anthropic-key" \ -H "Authorization: Bearer $AGENTLAIR_API_KEY" | grep -o '"ciphertext":"[^"]*"' | cut -d'"' -f4) PLAINTEXT=$(echo "$CIPHERTEXT" | openssl enc -aes-256-cbc -d -base64 -k "$LOCAL_PASSPHRASE") ``` ### Technical Analysis The optional encryption workflow uses AES-256-CBC without a message authentication code. CBC encryption provides confidentiality but does not independently provide integrity or authenticity. An attacker able to alter stored ciphertext may modify ciphertext blocks without the decryption process reliably detecting tampering. The OpenSSL commands also omit an explicit modern password-based key-derivation configuration, such as PBKDF2 with documented iteration and digest parameters. Security may therefore depend on OpenSSL version-specific defaults and the strength of the user-supplied passphrase, increasing the risk of offline passphrase guessing. The passphrase is supplied through the `-k "$LOCAL_PASSPHRASE"` command-line argument. On systems where process arguments are observable, this can disclose the passphrase to another local user or monitoring component. Once obtained, that passphrase can be used to decrypt any vault values protected with the same key. ### Attack Path #### Ciphertext-tampering path 1. An attacker obtains the ability to modi ...[truncated 1390 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace unauthenticated AES-CBC with authenticated encryption, preferably AES-256-GCM or XChaCha20-Poly1305. - Generate a unique cryptographically random nonce for each encryption operation and never reuse a nonce with the same key. - Bind relevant context, such as the vault key name and version, as authenticated associated data. - If deriving keys from passphrases, use a modern KDF such as Argon2id, scrypt, or PBKDF2 with explicitly documented salt and work-factor parameters. - Prefer a randomly generated encryption key stored in an operating-system keychain, hardware-backed keystore, or dedicated secret manager over a human-memorable passphrase. - Do not pass encryption secrets through command-line arguments. Use a protected file descriptor, secure prompt, keychain integration, or another OpenSSL input mechanism that does not expose the passphrase in the process list. - Fail closed when authentication-tag verification fails and never pass unauthenticated plaintext to downstream APIs. - Use a structured JSON parser instead of `grep` and `cut` to avoid fragile extraction and malformed-response handling. - Prevent plaintext and derived keys from being logged, printed, retained in shell history, or unnecessarily persisted in agent transcripts. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (7)

External Transmission

Medium
Category
Data Exfiltration
Content
primaryEnv: AGENTLAIR_API_KEY
    requires:
      bins:
        - curl
    tags:
      - credentials
      - secrets
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The skill claims credentials stay in the vault and only a vault token is held, but the examples explicitly retrieve plaintext secrets into local shell variables such as STRIPE_KEY and PLAINTEXT. That means secrets do exist in agent memory and may be exposed via process inspection, shell history mistakes, logs, or downstream command tracing, so the stated blast-radius reduction is overstated.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation includes immediate destructive DELETE operations for removing secrets and all versions without requiring confirmation guidance, backup advice, or user-approval language. In an agent context, this increases the risk of accidental irreversible credential loss or service disruption from an ambiguous or misinterpreted instruction.

External Transmission

Medium
Category
Data Exfiltration
Content
1. Store the Stripe key in vault:
```bash
curl -s -X PUT "https://agentlair.dev/v1/vault/stripe-live" \
  -H "Authorization: Bearer $AGENTLAIR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ciphertext": "sk_live_USER_PROVIDED_KEY", "metadata": {"label": "Stripe live key", "service": "stripe"}}'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
3. Use it:
```bash
curl -s "https://api.stripe.com/v1/balance" \
  -H "Authorization: Bearer $STRIPE_KEY"
```
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
SECRET="sk-ant-YOUR-KEY"
ENCRYPTED=$(echo -n "$SECRET" | openssl enc -aes-256-cbc -base64 -k "$LOCAL_PASSPHRASE")

curl -s -X PUT "https://agentlair.dev/v1/vault/anthropic-key" \
  -H "Authorization: Bearer $AGENTLAIR_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"ciphertext\": \"$ENCRYPTED\", \"metadata\": {\"encrypted\": \"aes-256-cbc\", \"label\": \"Anthropic API key\"}}"
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Intent-Code Divergence

Low
Confidence
95% confidence
Finding
The skill claims credentials stay in the vault and only a vault token is held, but the examples explicitly retrieve plaintext secrets into local shell variables such as STRIPE_KEY and PLAINTEXT. That means secrets do exist in agent memory and may be exposed via process inspection, shell history mistakes, logs, or downstream command tracing, so the stated blast-radius reduction is overstated.

Static analysis

No suspicious patterns detected.