Back to skill

Security audit

Gotchi DAO Voting

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it can submit real DAO votes using signing authority and has under-scoped credential and endpoint handling that users should review carefully.

Install only if you intend this skill to cast real Aavegotchi Snapshot votes from the configured wallet. Use dry-run first, verify the proposal ID, choice, wallet, space, and endpoints, and prefer setting BANKR_API_KEY explicitly for this skill rather than relying on cross-skill Bankr config discovery.

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

Warning
Location
scripts/lib.sh:37
Finding
Signed Vote Authorization Can Be Sent to an Untrusted Configurable Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lib.sh:37-53`, with the network sink at `scripts/vote.sh:234-242` **Vulnerability Type**: Unvalidated security-sensitive network destination **Risk Level**: Medium ### Vulnerable Code ```bash load_config() { [ -f "$CONFIG_FILE" ] || err "Config file not found: $CONFIG_FILE" WALLET="$(jq -r '.wallet // empty' "$CONFIG_FILE")" SPACE="$(jq -r '.space // empty' "$CONFIG_FILE")" SNAPSHOT_API="$(jq -r '.snapshotApiUrl // empty' "$CONFIG_FILE")" SEQUENCER="$(jq -r '.snapshotSequencer // empty' "$CONFIG_FILE")" [ -n "$WALLET" ] || err "Missing config.wallet" [ -n "$SPACE" ] || err "Missing config.space" [ -n "$SNAPSHOT_API" ] || err "Missing config.snapshotApiUrl" [ -n "$SEQUENCER" ] || err "Missing config.snapshotSequencer" normalize_wallet "$WALLET" >/dev/null } ``` The selected configuration file can also be overridden through an environment variable: ```bash CONFIG_FILE="${GOTCHI_DAO_CONFIG_FILE:-$SCRIPT_DIR/../config.json}" ``` After obtaining a valid Bankr signature, the script sends the signed payload to the unvalidated endpoint: ```bash jq -n \ --arg address "$WALLET" \ --arg sig "$SIGNATURE" \ --slurpfile data "$TMP_TYPED" \ '{address:$address,sig:$sig,data:$data[0]}' > "$TMP_PAYLOAD" VOTE_RESPONSE="$(curl -sS -X POST "$SEQUENCER" -H "Content-Type: application/json" -d @"$TMP_PAYLOAD")" ``` ### Technical Analysis The `snapshotSequencer` configuration value is only checked for non-emptiness. The code does not verify its scheme, hostname, port, or origin before sending a security-sensitive payload to it. The transmitted payload contains: - The user's wallet address. - The complete EIP-712 typed vote. - The vote choice and proposal identifier. - A valid Bankr-generated signature authorizing that exact vote. The bundled configuration points to the legitimate `https://seq.snapshot.org/` endpoint. However, a modified `config.json` or attacker-controlled `GOTCHI_ ...[truncated 1926 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Allowlist the official sequencer** - Require the normalized destination to match the intended origin, such as `https://seq.snapshot.org/`. - Reject alternate hosts, non-HTTPS schemes, embedded user information, and unexpected ports. 2. **Avoid configurable production security boundaries** - Hard-code the trusted Snapshot sequencer for normal operation. - If endpoint overrides are needed for testing, require an explicit development flag and clearly warn that signed data will be sent to a non-production destination. 3. **Validate before signing** - Validate the sequencer destination before calling Bankr so a signature is never generated when the eventual recipient is untrusted. - Display the validated destination before requesting the signature. 4. **Protect configuration integrity** - Require the configuration file to be owned by the current user and not writable by other users. - Treat `GOTCHI_DAO_CONFIG_FILE` as a privileged override and disable it in production execution where possible. 5. **Use strict network behavior** - Continue requiring TLS certificate verification. - Add suitable connection and request timeouts. - Do not follow redirects to a different origin for requests carrying signed authorization data. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code accurately supports the 'check active Aavegotchi DAO proposals' portion of the description by querying active proposals from Snapshot and displaying proposal details plus wallet voting power. However, this code chunk does not perform any voting action, does not prepare or submit a vote, and does not use Bankr or EIP-712 signatures. Since the declared description includes a significant capability—voting via Bankr EIP-712 signatures—that is absent from the supplied code, the description does not accurately represent this code chunk.

Ae1

High
Category
analysis-evasion
Content
- `./scripts/vote.sh [--dry-run] <proposal-id> <choice>`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README tells the user to run a live vote submission command immediately after a dry-run preview, but it does not clearly warn that this sends a real governance vote using the user's signing authority. In a DAO governance context, an accidental vote can have meaningful political and financial consequences and may be difficult or impossible to retract depending on Snapshot/space behavior.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares shell-capable behavior and external dependencies (`curl`, `jq`) but does not define any explicit tool scope such as `permissions` or `allowed-tools`. In agent environments, missing scope boundaries can allow broader-than-intended command execution or make it unclear what runtime capabilities are required, increasing the chance of misuse or unsafe invocation.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The function resolves a Bankr API key not only from its own environment but also from unrelated local skill configuration paths under ~/.openclaw. That creates cross-skill secret access and violates least privilege: this voting skill can silently consume credentials provisioned for another skill, which increases the blast radius if the skill is modified or compromised.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script loads a sensitive API key from environment and local files with no prompt, disclosure, or consent boundary, so operators may not realize this skill is harvesting existing secrets from their session or filesystem. In an agent-skill setting, silent secret discovery is risky because it enables unexpected credential use and makes abuse harder to notice.

External Transmission

Medium
Category
Data Exfiltration
Content
payload="$(jq -n --arg query "$query" --argjson variables "$variables_json" '{query:$query,variables:$variables}')" || err "Failed to build Snapshot query payload"

  curl -sS -X POST "$SNAPSHOT_API" \
    -H "Content-Type: application/json" \
    -d "$payload"
}
Confidence
70% 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
echo "📝 Signing vote with Bankr..."
SIGN_PAYLOAD="$(jq -n --slurpfile typed "$TMP_TYPED" '{signatureType:"eth_signTypedData_v4",typedData:$typed[0]}')"

SIGN_RESPONSE="$(curl -sS -X POST "https://api.bankr.bot/agent/sign" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d "$SIGN_PAYLOAD")"
Confidence
70% 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
echo "📝 Signing vote with Bankr..."
SIGN_PAYLOAD="$(jq -n --slurpfile typed "$TMP_TYPED" '{signatureType:"eth_signTypedData_v4",typedData:$typed[0]}')"

SIGN_RESPONSE="$(curl -sS -X POST "https://api.bankr.bot/agent/sign" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d "$SIGN_PAYLOAD")"
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
--slurpfile data "$TMP_TYPED" \
  '{address:$address,sig:$sig,data:$data[0]}' > "$TMP_PAYLOAD"

VOTE_RESPONSE="$(curl -sS -X POST "$SEQUENCER" -H "Content-Type: application/json" -d @"$TMP_PAYLOAD")"

echo "📬 Response:"
echo "$VOTE_RESPONSE" | jq '.'
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.