Back to skill

Security audit

Gotchi Finder

Security checks for vulnerabilities and agentic risk

Overview

This skill is a read-only Aavegotchi lookup and image-generation utility, with some documentation overclaims and auxiliary scripts that should be treated cautiously.

Install only if you are comfortable running npm dependencies and making public network requests for gotchi IDs. Prefer the documented show-gotchi.sh or find-gotchi.sh paths, avoid relying on the self-declared approval/zero-risk claims, and treat the auxiliary test and aging scripts as experimental unless reviewed further.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch-with-aging.js:25
Finding
GraphQL Injection Through an Unvalidated Gotchi Identifier<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch-with-aging.js:25-34`, with attacker-controlled input entering the call at `scripts/fetch-with-aging.js:123-124` **Vulnerability Type**: GraphQL injection caused by direct string interpolation **Risk Level**: Medium ### Vulnerable Code ```js async function querySubgraph(gotchiId) { const query = `{ aavegotchi(id: "${gotchiId}") { id name createdAt claimedAt hauntId baseRarityScore modifiedRarityScore } }`; ``` The value is obtained directly from the command line and passed to the vulnerable query construction: ```js const tokenId = process.argv[2] || '1484'; fetchGotchiWithAging(tokenId) ``` It reaches the network request through: ```js const subgraphData = await querySubgraph(tokenId); ``` ### Technical Analysis The command-line value is inserted directly inside a quoted GraphQL argument. The script does not verify that `tokenId` contains only digits, nor does it use typed GraphQL variables. A crafted value containing quotation marks and GraphQL syntax can terminate the intended `id` string and modify the query document sent to the configured Goldsky endpoint. This differs from the primary `fetch-gotchi.js` implementation, which validates its token ID as numeric. Although the endpoint exposes public blockchain information, the flaw permits callers to make the Skill issue queries beyond its intended single-token lookup behavior. ### Attack Path 1. An attacker or untrusted caller supplies a specially constructed command-line argument instead of a numeric Gotchi ID. 2. The value is assigned to `tokenId` without validation. 3. `querySubgraph()` interpolates the value into the GraphQL document. 4. The modified document is sent in an HTTPS POST request to `api.goldsky.com`. 5. If accepted by the GraphQL parser, the injected selection or additional query operation is processed by the remote service. ### Impact Assessment Successful ex ...[truncated 488 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate the CLI argument before making any request: ```js const tokenId = process.argv[2]; if (!tokenId || !/^\d+$/.test(tokenId)) { console.error('Usage: node fetch-with-aging.js <numeric-token-id>'); process.exit(1); } ``` 2. Enforce a reasonable numeric range and reject values that cannot be represented safely. 3. Use GraphQL variables rather than constructing the document with interpolation: ```js const query = ` query GetAavegotchi($id: ID!) { aavegotchi(id: $id) { id name createdAt claimedAt hauntId baseRarityScore modifiedRarityScore } } `; const data = JSON.stringify({ query, variables: { id: gotchiId } }); ``` 4. Add request timeouts, response-size limits, HTTP status validation, and GraphQL error handling to reduce denial-of-service exposure. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/get-birth-block.js:5
Finding
GraphQL Injection in Birth-Block Lookup<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get-birth-block.js:5-15`, with unvalidated CLI input at `scripts/get-birth-block.js:50-56` **Vulnerability Type**: GraphQL injection caused by direct string interpolation **Risk Level**: Medium ### Vulnerable Code ```js async function getBirthBlock(tokenId) { const query = ` query { aavegotchi(id: "${tokenId}") { id createdAt createdBlockNumber timesTraded } } `; ``` The interpolated value is taken directly from the command line: ```js const tokenId = process.argv[2]; if (!tokenId) { console.error('Usage: node get-birth-block.js <tokenId>'); process.exit(1); } getBirthBlock(tokenId).then(result => { ``` ### Technical Analysis The script checks only that an argument exists. It does not ensure that the supplied identifier is numeric or escape it before placing it inside a GraphQL string literal. Consequently, a caller can supply quotation marks and GraphQL syntax that alter the structure of the outbound query. The resulting attacker-influenced document is sent to the hardcoded public Goldsky subgraph. ### Attack Path 1. A caller invokes `get-birth-block.js` with crafted GraphQL syntax as the token ID. 2. The existence check accepts the argument. 3. The value is inserted verbatim into the `aavegotchi(id: "...")` expression. 4. The script serializes and sends the altered query to the public subgraph. 5. The remote endpoint processes the injected query if it is syntactically valid, and the script buffers and prints the response. ### Impact Assessment An attacker can make the Skill send queries outside the intended birth-block lookup shape. This may expose additional public subgraph data, create expensive operations, consume response-processing resources, or facilitate abuse of the third-party service. No secret credentials are attached to the request, and no evidence indicates access to private blockchain or local system data. The ob ...[truncated 118 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject every identifier that is not strictly numeric: ```js const tokenId = process.argv[2]; if (!tokenId || !/^\d+$/.test(tokenId)) { console.error('Usage: node get-birth-block.js <numeric-token-id>'); process.exit(1); } ``` 2. Replace interpolation with a typed GraphQL variable: ```js const query = ` query GetBirthBlock($id: ID!) { aavegotchi(id: $id) { id createdAt createdBlockNumber timesTraded } } `; const data = JSON.stringify({ query, variables: { id: tokenId } }); ``` 3. Check the HTTP status and GraphQL `errors` field before returning data. 4. Configure a request timeout and a maximum accepted response size. 5. Add tests using quotation marks, braces, fragments, and additional operations to confirm that malformed identifiers are rejected locally. ]]>

T08 · Insecure Dependencies

Note
Location
package.json:17
Finding
Non-Reproducible Dependency Installation Using Mutable Version Ranges<![CDATA[ ## Vulnerability Details **File Location**: `package.json:17-20`; installation is instructed at `README.md:7-10` and `SKILL.md:196-199` **Vulnerability Type**: Unpinned dependency resolution and missing lockfile **Risk Level**: Low ### Vulnerable Code ```json "dependencies": { "ethers": "^6.11.1", "sharp": "^0.33.0" } ``` The documented installation command is: ```bash npm install ``` No package lockfile was present in the audited project structure. ### Technical Analysis Caret version ranges permit npm to install newer compatible releases than those originally reviewed. Without a committed `package-lock.json`, transitive dependency versions and integrity hashes are not fixed, so two installations performed at different times can execute different third-party code. This is particularly relevant because `sharp` includes native components. The audit found no evidence that `ethers`, `sharp`, or their current maintainers are malicious; the issue is the inability to reproduce and verify the exact dependency graph represented by this artifact. ### Attack Path 1. A user follows the documentation and runs `npm install`. 2. npm resolves the mutable direct and transitive dependency ranges at installation time. 3. A newer allowed package release is selected instead of the version originally tested. 4. If an allowed future release or transitive dependency is compromised, its installation or runtime code executes with the installing user's privileges. 5. The compromised dependency can affect Skill execution, including blockchain requests and local output processing. ### Impact Assessment A compromised resolved dependency would execute with the same filesystem, network, and process privileges as the user running the Skill. It could potentially read user-accessible data, alter generated files, or make unauthorized network requests. This report does not establish an existing malicious dependency. The confirmed weakness is non-reproducible dependency s ...[truncated 73 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Generate and commit a reviewed `package-lock.json`. 2. Replace documented `npm install` deployment instructions with: ```bash npm ci ``` 3. Pin direct dependencies to exact reviewed versions where practical: ```json "dependencies": { "ethers": "6.11.1", "sharp": "0.33.0" } ``` 4. Review lockfile changes as security-sensitive changes and retain npm integrity hashes. 5. Run dependency vulnerability and provenance checks in continuous integration. 6. Update dependencies through controlled, tested pull requests rather than resolving mutable versions during production installation. 7. Consider installation policies that disable unnecessary lifecycle scripts, where compatible with the native dependency requirements. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The finding indicates a chain/source mismatch: the skill claims Base mainnet but may use a Polygon subgraph API, along with hardcoded test queries and incomplete field retrieval. This is particularly dangerous because users may make decisions based on incorrect chain data provenance, and the combination of mislabeling plus external API dependence can produce silently wrong results while the document aggressively asserts zero risk and approval status.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The implementation materially differs from the skill description: it fetches portal SVGs by status and haunt ID rather than fetching an Aavegotchi by token ID with full traits and image rendering behavior. In an agent skill ecosystem, this mismatch is security-relevant because users or downstream agents may trust the manifest to decide what data the skill accesses and displays, enabling deceptive or misleading behavior under false pretenses.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill advertises shell and environment-driven behavior but does not declare any explicit tool scope such as permissions or allowed-tools. That creates an authorization and review gap: an agent may execute shell commands or access environment variables without a clearly bounded contract, increasing the chance of unintended command execution or exposure of RPC endpoints and other sensitive runtime data.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest says the skill fetches an Aavegotchi by ID from Base mainnet, renders its on-chain SVG to PNG, and displays full traits. This file instead computes an age-based bonus from timestamps and returns a helper function, with no logic to fetch gotchi metadata, render SVG, convert images, or display traits.

Intent-Code Divergence

Medium
Confidence
92% confidence
Finding
The comments describe finding the birth timestamp by querying mint/Transfer events, but the function never uses the provided tokenId, never performs an event query, and ultimately just returns a closure that requires an externally supplied birthTimestamp. This is an active contradiction between the stated intent in comments and the actual implementation.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The script behavior does not match the stated skill purpose: it queries a centralized website API instead of retrieving data from Base mainnet on-chain sources. This creates an integrity and trust problem because users may believe they are seeing canonical on-chain data when the result is actually whatever the remote API returns, and availability/privacy also become dependent on that third-party service.

External Transmission

Medium
Category
Data Exfiltration
Content
echo "Fetching gotchi #$GOTCHI_ID from Aavegotchi API..."

# Try the official API endpoint
curl -s "https://api.aavegotchi.com/v1/aavegotchi/${GOTCHI_ID}" \
  -H "Accept: application/json" | jq .
Confidence
89% confidence
Finding
The script transmits user-supplied gotchi identifiers to an external domain, creating a privacy and dependency boundary outside the local skill. In this skill context, outbound network access is expected, but it is still security-relevant because the external service can log requests, return misleading data, or become unavailable, especially since the skill claims on-chain sourcing rather than a website API.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest description promises on-chain SVG display, PNG conversion, and presentation of complete gotchi stats. In this file, the implementation saves JSON and SVG files locally and logs some trait fields, but there is no PNG conversion or image display logic at all.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest says the skill 'converts to PNG, and displays' the on-chain SVG. In this file, the implementation writes metadata JSON and the SVG to disk, but performs no PNG conversion and no display/rendering logic. This is a direct mismatch between the advertised behavior and the implemented behavior.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The code omits the manifest-promised PNG conversion and full trait/stat display, so consumers may believe they are receiving richer processed output than the script actually provides. This discrepancy can mislead automation, break security assumptions about output format, and make it easier to substitute incomplete or unexpected data into downstream workflows.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes a skill focused on fetching an Aavegotchi by ID from Base, rendering its SVG/PNG image, and showing complete gotchi stats. This file instead adds separate behavior centered on querying a subgraph, calculating custom aging milestones, and reporting a derived 'full BRS (website)' metric, which goes beyond the stated image-and-traits retrieval scope.

External Transmission

Medium
Category
Data Exfiltration
Content
const https = require('https');

const SUBGRAPH_URL = 'https://api.goldsky.com/api/public/project_cm4b9xy95tko101tb1tyxaqw5/subgraphs/aavegotchi-core-base/1.0.0/gn';

async function getBirthBlock(tokenId) {
  const query = `
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
const https = require('https');

const SUBGRAPH_URL = 'https://api.goldsky.com/api/public/project_cm4b9xy95tko101tb1tyxaqw5/subgraphs/aavegotchi-core-base/1.0.0/gn';

async function getBirthBlock(tokenId) {
  const query = `
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
#!/bin/bash

# Query the Polygon subgraph first to see what fields exist
curl -s -X POST https://api.thegraph.com/subgraphs/name/aavegotchi/aavegotchi-core-matic \
  -H "Content-Type: application/json" \
  -d '{
    "query": "{ aavegotchi(id: \"1484\") { id name createdAt claimedAt gotchiId hauntId baseRarityScore modifiedRarityScore kinship level } }"
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.