Back to skill

Security audit

Sign-in with Agent

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent SIWA wallet/authentication guide, but it handles signing, payments, and secrets and includes examples with unsafe defaults or missing safeguards.

Review and harden the examples before installing or using this skill with real funds or production services: pin package and container versions, require strong SIWA secrets with no fallback, require replay protection for state-changing requests, add explicit approval and spending limits for x402 payments, and keep wallet/provider credentials in a managed secret store.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
server-side/skill.md:86
Finding

Predictable fallback secret permits authentication receipt forgery

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
server-side/skill.md:190
Finding

Protected request examples omit replay protection

Content
View full analysis
{ try { // Verify the ERC-8128 signed request const result = await verifyAuthenticatedRequest(req, { receiptSecret: SIWA_SECRET, }); if (!result.valid) { return res.status(401).json({ error: result.error }); } ``` The Next.js example repeats the same pattern: ```typescript export async function POST(req: Request) { const result = await verifyAuthenticatedRequest(req, { receiptSecret: SIWA_SECRET, }); if (!result.valid) { return NextResponse.json({ error: result.error }, { status: 401 }); } ``` The later security example characterizes the replay store as optional: ```typescript const result = await verifyAuthenticatedRequest(req, { receiptSecret: process.env.SIWA_SECRET!, // Optional: nonce store for replay protection nonceStore: myNonceStore, }); ``` ### Technical Analysis An HTTP message signature authenticates the request contents but does not, by itself, establish that the request has not already been accepted. A captured signed request remains cryptographically valid until a timestamp, receipt, or other validity boundary expires. The examples do not provide a nonce store to `verifyAuthenticatedRequest()`. The project documentation identifies the nonce store as the replay-protection mechanism, but marks it as optional and omits it from canonical state-changing route examples. This is particularly dangerous for `POST` operations because a byte-for-byte replay may repeat the same authenticated action. TLS protects requests in transit but d ...[truncated 1241 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
skill.md:82
Finding

x402 client example trusts attacker-controlled payment terms without policy validation

Content
View full analysis
(header!); // 3. Pick a payment option and construct payload const option = accepts[0]; const payload: PaymentPayload = { signature: "0x...", // sign the payment with your wallet payment: { scheme: option.scheme, network: option.network, amount: option.amount, asset: option.asset, payTo: option.payTo, }, resource, }; // 4. Retry with both SIWA auth + payment header const retryRequest = await signAuthenticatedRequest( new Request("https://api.example.com/premium", { method: "POST", headers: { "Payment-Signature": encodeX402Header(payload), }, }), receipt, signer, 84532, ); const paidRes = await fetch(retryRequest); } ``` ### Technical Analysis The `Payment-Required` header is controlled by the remote API. The example decodes that header, chooses `accepts[0]`, and copies the remote values directly into the wallet payment payload. No local validation is performed for: - Maximum payment amount - Expected blockchain network - Approved token or asset contract - Approved recipient address - Expected payment scheme - Resource and origin binding - Timeout limits - Whether the recipient or amount requires user approval A malicious API, compromised server, DNS or routing attack, or application-level redirect can therefore provide payment terms that transfer an excessive amount or direct payment to an attacker-selected address. Although the sample uses a placeholder signature, it explicitly instructs the caller to sign the resulting payment with the wallet. ### Attack Path 1. ...[truncated 1124 chars]
Remediation
View remediation
candidate.scheme === EXPECTED_SCHEME && candidate.network === EXPECTED_NETWORK && candidate.asset.toLowerCase() === EXPECTED_ASSET.toLowerCase() && APPROVED_RECIPIENTS.has(candidate.payTo.toLowerCase()) && BigInt(candidate.amount) <= MAX_PAYMENT ); if (!option) { throw new Error("No acceptable payment option"); } ``` Additional hardening should include: - Bind the payment resource to the exact requested HTTPS origin, path, method, and expected service. - Reject redirects to a different origin before processing payment requirements. - Apply per-request, per-recipient, daily, and aggregate spending limits. - Require explicit user approval for new recipients, new assets, production networks, or payments above a low threshold. - Validate numeric fields with strict bounds and reject malformed, negative, overflowing, or noncanonical values. - Validate `maxTimeoutSeconds` and payment expiration. - Present the recipient, asset, network, and human-readable amount before approval. - Use a dedicated low-balance wallet or constrained payment account rather than an unrestricted identity wallet. - Record payment intents and settlement results to prevent duplicate payment. ]]>

T08 · Insecure Dependencies

Warning
Location
skill.md:13
Finding

Security-critical dependencies and keyring container are not pinned to immutable versions

Content
View full analysis
Remediation
View remediation
``` - Pin provider SDKs and `viem` to exact compatible versions. - Commit and enforce a lockfile in executable example projects. - Use reproducible installation commands such as `npm ci` rather than unconstrained installation. - Pin the keyring proxy image by immutable digest: ```bash docker run ... ghcr.io/builders-garden/siwa-keyring-proxy@sha256: ``` - Verify package provenance, publisher identity, release signatures, and container attestations. - Generate and review a software bill of materials for wallet-facing deployments. - Run dependency vulnerability and malicious-package scanning in CI. - Review updates before changing pinned versions, especially signer and key-management components. - Isolate wallet components with restricted egress, minimal filesystem access, and narrowly scoped credentials to reduce the impact of a compromised dependency. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (87)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CLAUDE.md (reported line 16)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CLAUDE.md (reported line 17)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 29)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 154)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 160)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 168)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/security-model.md (reported line 102)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CLAUDE.md (reported line 16)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CLAUDE.md (reported line 142)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 31)May include surrounding context.

Set KEYRING_PROXY_SECRET (shared HMAC secret) and either KEYSTORE_PASSWORD (for encrypted-file backend) or AGENT_PRIVATE_KEY (to use an existing wallet). After deployment, configure your agent with:

text
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>

Memory Manipulation

High
Category
Memory Poisoning
Confidence
80% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · CLAUDE.md (reported line 120)May include surrounding context.

cd /home/node/.openclaw/workspace/siwa/packages/siwa-testing && pnpm run agent test-erc8128

text

### 9. Reset State

Clears SIWA_IDENTITY.md to start fresh.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · CLAUDE.md (reported line 142)May include surrounding context.

Create Signer

typescript
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";

const signer = createKeyringProxySigner({
  proxyUrl: process.env.KEYRING_PROXY_URL!,

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 43)May include surrounding context.

Create Signer

typescript
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";

const signer = createKeyringProxySigner({
  proxyUrl: process.env.KEYRING_PROXY_URL!,

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 45)May include surrounding context.

Create Signer

typescript
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";

const signer = createKeyringProxySigner({
  proxyUrl: process.env.KEYRING_PROXY_URL!,

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 175)May include surrounding context.

Create Signer

typescript
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";

const signer = createKeyringProxySigner({
  proxyUrl: process.env.KEYRING_PROXY_URL!,

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/security-model.md (reported line 100)May include surrounding context.

Create Signer

typescript
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";

const signer = createKeyringProxySigner({
  proxyUrl: process.env.KEYRING_PROXY_URL!,

Credential Access

High
Category
Privilege Escalation
Confidence
89% confidence
Finding

This example normalizes passing a shared HMAC secret (proxySecret) directly from environment variables into application code without any surrounding guidance on scoping, storage, rotation, or secret-management controls. Because this secret authorizes signing requests to a key-holding proxy, compromise of the application environment or logs could allow unauthorized use of the signing service and abuse of the protected wallet.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 46)May include surrounding context.

import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";

const signer = createKeyringProxySigner({ proxyUrl: process.env.KEYRING_PROXY_URL!, proxySecret: process.env.KEYRING_PROXY_SECRET!, });

text

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

The direct use of KEYRING_PROXY_SECRET for signer operations reinforces a single shared-secret trust model for access to a signing proxy. In this context the component controls cryptographic signing, so leakage of the secret materially enables unauthorized signature requests even if the private key stays server-side.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 47)May include surrounding context.

const signer = createKeyringProxySigner({ proxyUrl: process.env.KEYRING_PROXY_URL!, proxySecret: process.env.KEYRING_PROXY_SECRET!, });

text

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

Using the same shared proxySecret for wallet creation operations is high impact because wallet provisioning is a privileged action against the keystore proxy. If the secret is compromised, an attacker may be able to create or operate wallets through the proxy and misuse the signing infrastructure.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 155)May include surrounding context.

md
// Create a new wallet (stored encrypted in the proxy)
const address = await createWallet({
  proxyUrl: process.env.KEYRING_PROXY_URL!,
  proxySecret: process.env.KEYRING_PROXY_SECRET!,
});

// Get the wallet address

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

Again, the privileged keystore interaction depends on a long-lived shared secret passed from the environment. In a signing/key-management service, weak secret hygiene can translate directly into unauthorized access to wallet operations and indirect compromise of agent identity.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 161)May include surrounding context.

// Get the wallet address const addr = await getAddress({ proxyUrl: process.env.KEYRING_PROXY_URL!, proxySecret: process.env.KEYRING_PROXY_SECRET!, });

text

Credential Access

High
Category
Privilege Escalation
Confidence
90% confidence
Finding

The environment variable example explicitly uses a shared HMAC secret for authenticating to a key-signing proxy but does not provide security warnings or operational safeguards. Because this secret gates access to signing operations, mishandling it could enable unauthorized signing, wallet misuse, and impersonation of the agent.

Content

Scanner excerpt · keyring-proxy/skill.md (reported line 169)May include surrounding context.

bash
KEYRING_PROXY_URL=https://your-proxy.up.railway.app
KEYRING_PROXY_SECRET=your-shared-hmac-secret

Architecture

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/security-model.md (reported line 26)May include surrounding context.

md
| --------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| **Prompt injection exfiltration** | Malicious input instructs the agent to read and leak the private key | Key is never in any file the agent reads into context                                 |
| **Context window leakage**        | Key appears in the agent's working memory / LLM context              | Key is loaded inside a function, used, and discarded — never returned                 |
| **File system snooping**          | Another process reads the key from disk                              | OS keychain uses encrypted storage with access controls; V3 keystore is AES-encrypted |
| **Log / error exposure**          | Key appears in stack traces, console output, or error messages       | Signing functions return only signatures, never raw keys                              |
| **Accidental commit**             | Key is committed to version control                                  | No file in the project ever contains the plaintext key                                |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/siwa-vs-siwx.md (reported line 37)May include surrounding context.

md
If an attacker captures the `SIGN-IN-WITH-X` header value:

- Replay it on `DELETE /api/account` even though it was signed for `GET /api/data`
- Replay it with a completely different request body
- Replay it on any route on the same domain until the nonce expires
- Use it from a different IP, user-agent, or context

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The documented reset command deletes or clears persistent identity state without an explicit warning about data loss, scope, or a confirmation step. In an agent setting, this can lead to accidental loss of registration context or operational disruption if the command is run reflexively during troubleshooting.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.