Back to skill

Security audit

Stellar Agent Wallet

Security checks for vulnerabilities and agentic risk

Overview

This is a clearly disclosed Stellar wallet skill, but it can move real funds and has under-scoped unattended payment and async polling behavior that users should review carefully.

Install only with a dedicated low-balance hot wallet, test on testnet first, and avoid --yes or --max-auto on mainnet unless you also pin expected recipient, asset, and amount. Treat any paid API URL as able to influence where funds go and where async polling connects; do not use this with a primary wallet or broad automation until those controls are tightened.

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)

T09 · Insecure Skill Coding Practices

Warning
Location
skills/pay-per-call/run.ts:795
Finding

Unvalidated Server-Supplied Poll URL Enables SSRF and a Wallet Signing Oracle

Content
View full analysis
| { error: string }> { const owner = keypair.publicKey(); let res: Response; try { res = await fetch(`${pollUrl}/challenge`, { headers: { "X-Stellar-Owner": owner }, }); } catch (err) { return { error: `challenge request failed — ${(err as Error).message}` }; } if (!res.ok) { let detail = ""; try { detail = ((await res.json()) as any)?.error ?? ""; } catch { /* non-JSON body */ } return { error: `challenge ${res.status}${detail ? ` — ${detail}` : ""}` }; } let body: { nonce?: string }; try { body = (await res.json()) as { nonce?: string }; } catch { return { error: "challenge response was not JSON" }; } if (!body.nonce) return { error: "challenge response had no nonce" }; const message = new TextEncoder().encode( `${OWNERSHIP_DOMAIN}:${jobId}:${body.nonce}`, ); if (message.length === 32) { return { error: "refusing to sign a 32-byte payload" }; } const signature = keypair.sign(Buffer.from(message)).toString("base64"); return { "X-Stellar-Owner": owner, "X-Stellar-Nonce": body.nonce, "X-Stellar-Signature": signature, }; } ``` ```ts res = await fetch(pollUrl, { headers: authHeaders }); ``` ```ts if (res.status === 202) { const pollUrl = res.headers.get("x-job-poll-url"); const jobId = res.headers.get("x-job-id"); if (pollUrl) { console.error(`⏳ Async job started (id=${jobId ?? "unknown"})`); console.error(` Poll URL: ${pollUrl}`); const result = await pollJobStatus( pollUrl, new URL(pollUrl).pathname.split("/").pop() ?? "", Keypair.fromSecret(signe ...[truncated 2588 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
skills/pay-per-call/run.ts:720
Finding

Unattended Mainnet Payments Can Sign Unbound Server-Controlled Transfer Parameters

Content
View full analysis
{ const { amountUsd, humanAmount, payTo, args, network } = opts; if (network !== "pubnet") return; if (args.yes) return; if (args.maxAutoUsd !== undefined) { if (amountUsd <= args.maxAutoUsd) { console.error( `[autopay] $${humanAmount} USDC → ${payTo} auto-signed ` + `(--max-auto $${args.maxAutoUsd.toFixed(2)}, session-only, ` + `no confirmation asked — drop the flag to restore prompts)`, ); return; } } const ok = await promptConfirm( `Pay $${humanAmount} USDC on mainnet? (yes/no) `, ); if (!ok) { console.error("Aborted."); process.exit(0); } } ``` ```ts const expectations: ChallengeExpectations = { payTo: args.expectPayTo, asset: args.expectAsset, amountUsdc: args.expectAmountUsdc, amountTolerance: args.expectAmountTolerance, }; const hasAnyExpectation = expectations.payTo !== undefined || expectations.asset !== undefined || expectations.amountUsdc !== undefined; if (hasAnyExpectation) { const mismatches = validateChallenge(challenge, expectations); if (mismatches) { console.error("❌ Challenge does not match expected values:"); for (const m of mismatches) console.error(` - ${m}`); console.error(""); console.error(" Refusing to sign. The 402 server may be compromised,"); console.error(" the URL may be wrong, or the catalog is stale."); process.exit(3); } console.error("✓ Challenge matches --expect-* values."); console.error(""); } ``` ```ts await gateMainnetPayment({ amountUsd, humanAmount, payTo: challenge.pa ...[truncated 2975 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (59)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill is not just a wallet interface; it also documents broad secret-loading behavior, including plaintext secret files, .env fallbacks, sibling-install directory search, and external command execution to export identities. Those behaviors materially expand the attack surface because an agent handling payments may also discover and consume credentials from places a user may not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is not just a wallet interface; it also documents broad secret-loading behavior, including plaintext secret files, .env fallbacks, sibling-install directory search, and external command execution to export identities. Those behaviors materially expand the attack surface because an agent handling payments may also discover and consume credentials from places a user may not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill is not just a wallet interface; it also documents broad secret-loading behavior, including plaintext secret files, .env fallbacks, sibling-install directory search, and external command execution to export identities. Those behaviors materially expand the attack surface because an agent handling payments may also discover and consume credentials from places a user may not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill is not just a wallet interface; it also documents broad secret-loading behavior, including plaintext secret files, .env fallbacks, sibling-install directory search, and external command execution to export identities. Those behaviors materially expand the attack surface because an agent handling payments may also discover and consume credentials from places a user may not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill is not just a wallet interface; it also documents broad secret-loading behavior, including plaintext secret files, .env fallbacks, sibling-install directory search, and external command execution to export identities. Those behaviors materially expand the attack surface because an agent handling payments may also discover and consume credentials from places a user may not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill is not just a wallet interface; it also documents broad secret-loading behavior, including plaintext secret files, .env fallbacks, sibling-install directory search, and external command execution to export identities. Those behaviors materially expand the attack surface because an agent handling payments may also discover and consume credentials from places a user may not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill is not just a wallet interface; it also documents broad secret-loading behavior, including plaintext secret files, .env fallbacks, sibling-install directory search, and external command execution to export identities. Those behaviors materially expand the attack surface because an agent handling payments may also discover and consume credentials from places a user may not expect.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill is not just a wallet interface; it also documents broad secret-loading behavior, including plaintext secret files, .env fallbacks, sibling-install directory search, and external command execution to export identities. Those behaviors materially expand the attack surface because an agent handling payments may also discover and consume credentials from places a user may not expect.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 155)May include surrounding context.

md
g key is loaded from `.stellar-secret` (mode 600) or a Stellar CLI identity by `scripts/src/secret.ts` and passed as a function argument to `scripts/src/stellar

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 162)May include surrounding context.

md
g key is loaded from `.stellar-secret` (mode 600) or a Stellar CLI identity by `scripts/src/secret.ts` and passed as a function argument to `scripts/src/stellar

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

The phrase "The identity path prints no warning" weakens operator visibility around a highly sensitive action: loading spend-capable wallet credentials. In a wallet skill that can move mainnet funds, suppressing prominent warnings for one credential source can normalize silent signing conditions and reduce the chance a user notices which key source is active.

Content

Scanner excerpt · SKILL.md (reported line 173)May include surrounding context.

md
**Prefer `--identity <name>` for anything beyond throwaway testing.** It delegates key storage to the Stellar CLI, so the secret never has to exist as a plaintext file in your working directory or in a `.env` alongside your other configuration. The identity path prints no warning.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 225)May include surrounding context.

md
Each sub-skill has its own `SKILL.md` and `run.ts` in `skills/<name>/`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 230)May include surrounding context.

md
Each sub-skill has its own `SKILL.md` and `run.ts` in `skills/<name>/`.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 252)May include surrounding context.

md
./node_modules/.bin/tsx skills/onboard/run.ts

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 259)May include surrounding context.

md
./node_modules/.bin/tsx skills/onboard/run.ts

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 255)May include surrounding context.

md
# Run: ./node_modules/.bin/tsx skills/check-balance/add-trustline.ts --network pubnet

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 263)May include surrounding context.

md
./node_modules/.bin/tsx skills/check-balance/run.ts

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 415)May include surrounding context.

md
./node_modules/.bin/tsx skills/check-balance/run.ts

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 267)May include surrounding context.

md
SERVICE=$(./node_modules/.bin/tsx skills/discover/run.ts --query "web search" --pick-one --json)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 272)May include surrounding context.

md
./node_modules/.bin/tsx skills/pay-per-call/run.ts "https://apiserver.mpprouter.dev$PATH_" \

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 378)May include surrounding context.

md
./node_modules/.bin/tsx skills/send-raw/run.ts --to <receiverAddress> \

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/src/cli-config.ts (reported line 25)May include surrounding context.

ts
*
 * Rules enforced here:
 *   1. Secrets come from a file path. If the file is missing, falls back
 *      to STELLAR_SECRET in .env.prod then .env (same directory).
 *   2. The value must match the Stellar strkey pattern (S... 56 chars).
 *   3. We install a stdout/stderr wrapper that replaces any accidental
 *      occurrence of the secret with [REDACTED].

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/src/secret.ts (reported line 6)May include surrounding context.

ts
*
 * Rules enforced here:
 *   1. Secrets come from a file path. If the file is missing, falls back
 *      to STELLAR_SECRET in .env.prod then .env (same directory).
 *   2. The value must match the Stellar strkey pattern (S... 56 chars).
 *   3. We install a stdout/stderr wrapper that replaces any accidental
 *      occurrence of the secret with [REDACTED].

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/src/secret.ts (reported line 89)May include surrounding context.

ts
*
 * Rules enforced here:
 *   1. Secrets come from a file path. If the file is missing, falls back
 *      to STELLAR_SECRET in .env.prod then .env (same directory).
 *   2. The value must match the Stellar strkey pattern (S... 56 chars).
 *   3. We install a stdout/stderr wrapper that replaces any accidental
 *      occurrence of the secret with [REDACTED].

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

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

Content

Scanner excerpt · scripts/src/secret.ts (reported line 348)May include surrounding context.

ts
*
 * Rules enforced here:
 *   1. Secrets come from a file path. If the file is missing, falls back
 *      to STELLAR_SECRET in .env.prod then .env (same directory).
 *   2. The value must match the Stellar strkey pattern (S... 56 chars).
 *   3. We install a stdout/stderr wrapper that replaces any accidental
 *      occurrence of the secret with [REDACTED].

Static analysis

No suspicious patterns detected.