T09 · Insecure Skill Coding Practices
- Location
server-side/skill.md:86- Finding
Predictable fallback secret permits authentication receipt forgery
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
server-side/skill.md:86Predictable fallback secret permits authentication receipt forgery
server-side/skill.md:190Protected request examples omit replay protection
skill.md:82x402 client example trusts attacker-controlled payment terms without policy validation
skill.md:13Security-critical dependencies and keyring container are not pinned to immutable versions
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
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:
KEYRING_PROXY_URL=https://your-keyring-proxy.up.railway.app
KEYRING_PROXY_SECRET=<your-shared-secret>
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.
cd /home/node/.openclaw/workspace/siwa/packages/siwa-testing && pnpm run agent test-erc8128
### 9. Reset State
Clears SIWA_IDENTITY.md to start fresh.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";
const signer = createKeyringProxySigner({
proxyUrl: process.env.KEYRING_PROXY_URL!,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";
const signer = createKeyringProxySigner({
proxyUrl: process.env.KEYRING_PROXY_URL!,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";
const signer = createKeyringProxySigner({
proxyUrl: process.env.KEYRING_PROXY_URL!,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";
const signer = createKeyringProxySigner({
proxyUrl: process.env.KEYRING_PROXY_URL!,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";
const signer = createKeyringProxySigner({
proxyUrl: process.env.KEYRING_PROXY_URL!,
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.
import { createKeyringProxySigner } from "@buildersgarden/siwa/signer";
const signer = createKeyringProxySigner({ proxyUrl: process.env.KEYRING_PROXY_URL!, proxySecret: process.env.KEYRING_PROXY_SECRET!, });
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.
const signer = createKeyringProxySigner({ proxyUrl: process.env.KEYRING_PROXY_URL!, proxySecret: process.env.KEYRING_PROXY_SECRET!, });
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.
// 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
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.
// Get the wallet address const addr = await getAddress({ proxyUrl: process.env.KEYRING_PROXY_URL!, proxySecret: process.env.KEYRING_PROXY_SECRET!, });
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.
KEYRING_PROXY_URL=https://your-proxy.up.railway.app
KEYRING_PROXY_SECRET=your-shared-hmac-secret
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| --------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| **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 parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
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
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.
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.
No suspicious patterns detected.