Back to skill

Security audit

A2a Agent Signup

Security checks for vulnerabilities and agentic risk

Overview

This CLI mostly matches its stated signup purpose, but it needs review because installation persistently changes the user environment and one payment-browser path can execute a shell command using unvalidated remote data.

Install only if you are comfortable with a CLI that registers you with the A2A marketplace, charges a small USDC fee to the documented wallet, stores a wallet address and auth token locally, and changes your shell PATH. Review or remove the postinstall/setup shell changes, avoid running it in a source repository unless .env is ignored, and do not use an untrusted A2A_API_URL until the browser-opening command injection issue is fixed.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
index.js:272
Finding

Remote API Response Enables Shell Command Injection

Content
View full analysis

Vulnerability Details

File Location: index.js:272-291, 430-440
Vulnerability Type: Shell command injection through an untrusted signup session identifier
Risk Level: High

Vulnerable Code

The session data is accepted directly from the remote API:

js
async function createSignupSession(params) {
  const payload = {
    jsonrpc: '2.0',
    id: 1,
    method: 'createSignupSession',
    params: {
      walletAddress: params.walletAddress,
      name: params.name,
      bio: params.bio,
      specialization: params.specialization,
      serviceTitle: params.serviceTitle,
      serviceDescription: params.serviceDescription,
      price: typeof params.price === 'string' ? parseFloat(params.price) : params.price,
      currency: params.currency
    }
  };

  const response = await fetch(API_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });

  const data = await response.json();
  if (data.error) throw new Error(data.error.message);
  return data.result;
}

The remotely supplied session.sessionId is then embedded in a shell command:

js
if (paymentMethod === 'browser') {
  const paymentUrl = `${BASE_URL}/signup/${session.sessionId}`;
  console.log(`\n🌐 Opening payment page in browser...\n`);
  console.log(`   URL: ${paymentUrl}\n`);
  console.log('   Please complete the payment in your browser.\n');

  // Try to open in browser (if available)
  const { exec } = require('child_process');
  exec(`open "${paymentUrl}" || xdg-open "${paymentUrl}" || start "${paymentUrl}"`, () => {});
}

Technical Analysis

createSignupSession() trusts the JSON-RPC server's data.result object without validating the format of sessionId. The value flows into paymentUrl, which is interpolated into a command executed by child_process.exec().

exec() invokes a system shell. Quotatio ...[truncated 1945 chars]

Remediation
View remediation

Remediation Suggestions

  1. Do not use child_process.exec() to open the URL. Use spawn() or execFile() with shell processing disabled and pass the URL as a separate argument.
  2. Select the executable by platform rather than constructing an open || xdg-open || start shell expression.
  3. Validate session.sessionId before use with a strict allowlist matching the server's documented identifier format, such as ^[A-Za-z0-9_-]+$, with an explicit maximum length.
  4. Construct the URL with the URL API and encode the identifier as a path component.
  5. Reject malformed API responses by validating the complete response schema, including the expected types and presence of sessionId.
  6. Restrict A2A_API_URL to HTTPS and, if custom marketplace instances are not required, allowlist the official host.
  7. Consider a maintained cross-platform browser-opening library that does not expose input to a shell.

Example hardened approach:

js
const { spawn } = require('child_process');

if (!/^[A-Za-z0-9_-]{1,128}$/.test(session.sessionId)) {
  throw new Error('Invalid signup session identifier');
}

const paymentUrl = new URL(
  `/signup/${encodeURIComponent(session.sessionId)}`,
  BASE_URL
).toString();

if (process.platform === 'darwin') {
  spawn('open', [paymentUrl], { shell: false, detached: true });
} else if (process.platform === 'win32') {
  spawn('cmd.exe', ['/d', '/s', '/c', 'start', '', paymentUrl], {
    shell: false,
    detached: true
  });
} else {
  spawn('xdg-open', [paymentUrl], { shell: false, detached: true });
}
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
Findings (20)

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 · index.js (reported line 24)May include surrounding context.

js
})();
const SIGNUP_FEE_RECIPIENT = '0x26fc06D17Eb82638b25402D411889EEb69F1e7C5'; // Marc's wallet (hardcoded)
const CONFIG_PATH = path.join(process.env.HOME, '.a2a-agent-config');
const ENV_PATH = path.join(process.cwd(), '.env');
let AGENT_WALLET = process.env.AGENT_WALLET || ''; // Agent's wallet (from .env)

const SPECIALIZATIONS = [

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 · index.js (reported line 51)May include surrounding context.

js
return args;
}

// First-time setup: prompt for agent wallet if not in .env
async function setupWallet() {
  if (AGENT_WALLET) {
    return; // Already configured

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 · index.js (reported line 71)May include surrounding context.

js
return args;
}

// First-time setup: prompt for agent wallet if not in .env
async function setupWallet() {
  if (AGENT_WALLET) {
    return; // Already configured

Known Vulnerable Dependency: ws==8.17.1 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
96% confidence
Finding

The lockfile pins the transitive dependency ws to version 8.17.1, and the provided finding identifies two high-severity advisories affecting that exact version: uninitialized memory disclosure and memory-exhaustion denial of service. Because this package also has hasInstallScript=true and depends on ethers, which commonly uses websocket connectivity for blockchain RPC, the vulnerable library is plausibly reachable in realistic usage and can expose sensitive process memory or allow service disruption.

Content

No source excerpt is available for this finding.

Possible Typosquatting: 'enquirer' resembles popular package 'inquirer'

High
Category
Supply Chain
Confidence
70% confidence
Finding

Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Content

No source excerpt is available for this finding.

Possible Typosquatting: 'enquirer' resembles popular package 'inquirer'

High
Category
Supply Chain
Confidence
70% confidence
Finding

Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Content

No source excerpt is available for this finding.

YARA rule 'backdoor_persistence': Backdoor persistence with malicious payloads (shell commands, SSH key injection, hidden root users) [malware]

High
Category
YARA Match
Confidence
75% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · setup.sh (reported line 23)May include surrounding context.

sh
ate ~/bin if it doesn't exist
mkdir -p "$BIN_DIR"

# Install dependencies
cd "$SKILL_DIR"
npm install --quiet

# Create symlink
ln -sf "$SKILL_DIR/index.js" "$BIN_DIR/a2a-agent-signup"
chmod +x "$SKILL_DIR/index.js"

echo "✓ a2a-agent-signup linked to $BIN_DIR/a2a-agent-signup"

# Add ~/bin to PATH in ~/.bashrc if not already there
if ! grep -q 'export PATH="$HOME/bin:\$PATH"' ~/.bashrc; then
  echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
  echo "✓ Added ~/bin to ~/.bashrc"
fi

# Run the wizard
echo ""
echo "✓ Setup complete! Starting a2a-agent-signup..."
echo ""

# Run the script directly
node "$SKILL_DIR/index.js"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explicitly states that credentials are saved to ~/.a2a-agent-config, including an authToken, and also uses a local .env for wallet data, but it does not present a clear warning about local sensitive-data storage before onboarding the user. This can lead users to unknowingly leave authentication material and wallet identifiers in plaintext-like files that may be exposed through weak file permissions, backups, shared machines, or accidental commits.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

Creating a symlink in ~/bin and modifying PATH via ~/.bashrc establishes persistent command availability across sessions. In context this appears intended for convenience rather than covert persistence, but it still has security relevance because it changes shell execution behavior and could increase the impact of future tampering with the linked script or user bin directory.

Content

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

text

That's it! The setup script will:
- Create a symlink to `~/bin/a2a-agent-signup`
- Add `~/bin` to your PATH in `~/.bashrc`
- Load the PATH in your current shell
- Test that the command works

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill says the first run saves the wallet to a .env in the current directory, but it does not clearly warn users before doing so. Writing wallet information into the working directory can expose it to accidental source-control commits, broader file sharing, or other local processes, especially when users run the tool inside project folders.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The comments and UX text tell users the configured wallet is where they receive client payments, while the same wallet is also used as the account charged the registration fee. That mismatch can mislead users into funding or exposing the wrong wallet and may cause unintended charges from an address they did not intend to use for payments.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code prints a newly generated wallet private key directly to the terminal. Terminal output may be captured by shell history tools, logs, screen recording, remote sessions, or shoulder surfing, and anyone who obtains the key can fully control and drain the wallet.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · index.js (reported line 181)May include surrounding context.

js
// Get exchange rates
    let rates = { SHIB: 0, USDC: 1 };
    try {
      const ratesResp = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=shiba-inu,usd-coin&vs_currencies=usd');
      const ratesData = await ratesResp.json();
      rates.SHIB = ratesData['shiba-inu']?.usd || 0;
      rates.USDC = ratesData['usd-coin']?.usd || 1;

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The postinstall script writes to the user's home directory, creates a symlink in ~/bin, and changes executable permissions automatically at install time. Install-time side effects outside the package directory are risky because they occur without explicit runtime consent and can persistently alter the user's environment in ways that are not necessary for a normal npm package install.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The package silently modifies ~/bin during postinstall and creates or replaces a symlink without any warning in this file. This is dangerous because users and automated environments may install the package expecting dependency setup only, while the package instead performs persistent filesystem changes in the home directory.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · setup.sh (reported line 8)May include surrounding context.

sh
SKILL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
BIN_DIR="$HOME/bin"

# Create ~/bin if it doesn't exist
mkdir -p "$BIN_DIR"

# Install dependencies

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The setup instructions say the script will automatically modify ~/.bashrc, change PATH, and load those changes into the current shell, but do not clearly warn the user beforehand. While common for CLI tooling, automatic shell-profile modification creates persistence and command-resolution risk if users do not understand the change or if the installed path later contains untrusted executables.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 14)May include surrounding context.

json
"postinstall": "mkdir -p ~/bin && ln -sf \"$PWD/index.js\" ~/bin/a2a-agent-signup && chmod +x \"$PWD/index.js\" && echo \"✓ a2a-agent-signup linked to ~/bin\""
  },
  "dependencies": {
    "enquirer": "^2.4.1",
    "ethers": "^6.13.0",
    "qrcode": "^1.5.3"
  }

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 15)May include surrounding context.

json
},
  "dependencies": {
    "enquirer": "^2.4.1",
    "ethers": "^6.13.0",
    "qrcode": "^1.5.3"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · package.json (reported line 16)May include surrounding context.

json
"dependencies": {
    "enquirer": "^2.4.1",
    "ethers": "^6.13.0",
    "qrcode": "^1.5.3"
  }
}

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
index.js:440

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
index.js:13

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
index.js:383