Back to skill

Security audit

Element NFT Drops

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-built for Element NFT drop management, but it uses wallet credentials and has raw commands that can make live remote or blockchain changes without an enforced confirmation gate.

Install only if you are comfortable using a dedicated low-risk wallet and reviewing every preview before execution. Avoid invoking the advanced utility commands directly, treat terminal output/logs as sensitive, and prefer a locked dependency install rather than on-demand unpinned npx execution.

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
scripts/src/cli.ts:1686
Finding
Element Authorization Token Disclosed Through Standard Output<![CDATA[ ## Vulnerability Details **File Location**: `scripts/src/cli.ts:1686-1707` **Vulnerability Type**: Sensitive authentication-token disclosure **Risk Level**: Medium ### Vulnerable Code ```ts const authorization = payload.authorization ?? ( await createAuthorization(payload.chainMId) ).authorization; const result = await postCreateCollectionFlow( { chainMId: payload.chainMId, contractAddress: payload.contractAddress, authorization, imageFilePath: payload.imageFilePath ?? payload.preReveal, pollIntervalMs: payload.pollIntervalMs, timeoutMs: payload.timeoutMs }, { getCollectionContract: graphql.getCollectionContract, getMutateToken: graphql.getMutateToken, getCollectionDetailFromEditors: graphql.getCollectionDetailFromEditors, collectionEdit: graphql.collectionEdit } ); console.log(JSON.stringify({ authorization, ...result }, null, 2)); ``` ### Technical Analysis The `post-create-collection` command obtains or accepts an Element authorization token and then includes that token in its JSON output. Authorization tokens are bearer credentials: possession may be sufficient to perform authenticated actions without access to the wallet private key. Writing the token to standard output exposes it beyond the minimum scope required for the workflow. Standard output may be retained in terminal scrollback, Agent transcripts, CI logs, shell automation output, monitoring systems, or redirected files. This also conflicts with the Skill's reporting contract, which calls for user-visible lifecycle results rather than internal authentication material. The raw wallet private key is not disclosed by this code, but protection of the key does not mitigate reuse of an already-issued session token. ### Attack Path 1. A user or automated Agent invokes the `post-create-collection` command. 2. The command creates or receives an Element authorization token. 3. The command serializes the token under the `authorization ...[truncated 1059 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the authorization token from command output: ```ts console.log(JSON.stringify(result, null, 2)); ``` 2. Keep authorization material internal to the workflow and never include it in user-facing result objects. 3. Add recursive output sanitization that removes or masks fields such as `authorization`, `token`, `security_token`, cookies, signatures, and API keys before serialization. 4. Extend `redactKnownSecrets` so it protects temporary authorization and mutation tokens in addition to the wallet private key. 5. Add regression tests that inject a known token and verify it never appears in standard output, standard error, thrown errors, or structured logs. 6. If tokens previously appeared in retained logs, remove those logs where feasible and invalidate affected sessions. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/src/config.ts:6
Finding
Recoverable Shared GraphQL Credentials Embedded in Source Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/src/config.ts:6-25` **Vulnerability Type**: Hardcoded API credential and HMAC secret **Risk Level**: Medium ### Vulnerable Code ```ts const DEFAULT_GRAPHQL_TOKEN_A_BYTES = [ 122, 81, 98, 89, 106, 55, 82, 104, 67, 49, 86, 72, 73, 66, 100, 87, 85, 54, 51, 107, 105, 53, 65, 74, 75, 88, 108, 111, 97, 109, 68, 84 ]; const DEFAULT_GRAPHQL_TOKEN_B_BYTES = [ 85, 113, 67, 77, 112, 102, 71, 110, 51, 86, 121, 81, 69, 100, 106, 76, 107, 122, 74, 118, 57, 116, 78, 108, 103, 98, 75, 70, 68, 55, 79 ]; function decodeAsciiBytes(bytes: number[]): string { return String.fromCharCode(...bytes); } export function resolveElementGraphqlTokenA(): string { return decodeAsciiBytes(DEFAULT_GRAPHQL_TOKEN_A_BYTES); } export function resolveElementGraphqlTokenB(): string { return decodeAsciiBytes(DEFAULT_GRAPHQL_TOKEN_B_BYTES); } ``` The recovered values are subsequently used to create GraphQL gateway authentication headers in `scripts/src/api/graphql.ts:278-289`: ```ts const tokenA = input?.tokenA ?? resolveElementGraphqlTokenA(); const tokenB = input?.tokenB ?? resolveElementGraphqlTokenB(); const nonce = String(input?.nonce ?? randomInt(1000, 10000)); const timestamp = String(input?.timestamp ?? Math.floor(Date.now() / 1000)); const signature = createHmac("sha256", tokenB) .update(`${tokenA}${nonce}${timestamp}`) .digest("hex"); return { "x-api-key": tokenA, "x-api-sign": `${signature}.${nonce}.${timestamp}`, origin: "https://element.market", referer: "https://element.market/", "user-agent": "Mozilla/5.0" }; ``` ### Technical Analysis Two fixed GraphQL gateway credentials are stored as arrays of decimal ASCII values and reconstructed at runtime. This representation is obfuscation rather than encryption: anyone who can read the distributed Skill can recover both values immediately. One recovered value is sent as `x-api-key`; the other is used as the HMAC key for `x-api-sign`. An attacke ...[truncated 1853 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove shared secret material from the source code and published package. 2. Rotate the exposed values if Element treats either value as confidential or privileged. 3. Obtain scoped, revocable credentials through a secure runtime mechanism rather than embedding them in a client-distributed Skill. 4. Prefer short-lived credentials with narrowly limited API operations, audience, quotas, and expiration. 5. If these values are intentionally public browser-client identifiers, document that status and ensure the server does not use them as an authorization boundary. 6. Enforce sensitive-operation authorization using the wallet-authenticated session and server-side ownership checks, not a recoverable client HMAC key. 7. Add secret-scanning checks to the development and release pipeline, including detection of encoded or obfuscated credential constants. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (47)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the underlying implementation performs low-level auth and direct collection-edit operations without the required user-facing preview/confirmation controls, the skill could mutate remote state unexpectedly while operating with a sensitive wallet credential. The danger is increased by the mismatch between reassuring user-facing rules and potentially less constrained backend behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the underlying implementation performs low-level auth and direct collection-edit operations without the required user-facing preview/confirmation controls, the skill could mutate remote state unexpectedly while operating with a sensitive wallet credential. The danger is increased by the mismatch between reassuring user-facing rules and potentially less constrained backend behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the underlying implementation performs low-level auth and direct collection-edit operations without the required user-facing preview/confirmation controls, the skill could mutate remote state unexpectedly while operating with a sensitive wallet credential. The danger is increased by the mismatch between reassuring user-facing rules and potentially less constrained backend behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the underlying implementation performs low-level auth and direct collection-edit operations without the required user-facing preview/confirmation controls, the skill could mutate remote state unexpectedly while operating with a sensitive wallet credential. The danger is increased by the mismatch between reassuring user-facing rules and potentially less constrained backend behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
If the underlying implementation performs low-level auth and direct collection-edit operations without the required user-facing preview/confirmation controls, the skill could mutate remote state unexpectedly while operating with a sensitive wallet credential. The danger is increased by the mismatch between reassuring user-facing rules and potentially less constrained backend behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
If the underlying implementation performs low-level auth and direct collection-edit operations without the required user-facing preview/confirmation controls, the skill could mutate remote state unexpectedly while operating with a sensitive wallet credential. The danger is increased by the mismatch between reassuring user-facing rules and potentially less constrained backend behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
If the underlying implementation performs low-level auth and direct collection-edit operations without the required user-facing preview/confirmation controls, the skill could mutate remote state unexpectedly while operating with a sensitive wallet credential. The danger is increased by the mismatch between reassuring user-facing rules and potentially less constrained backend behavior.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The CLI exposes multiple state-changing utility commands such as post-settings, post-design, upload-prereveal, upload-design, post-create-collection, and create-token that execute immediately without the explicit preview/confirmation gate required by the skill contract. In this skill context, those commands can mutate remote drop configuration, upload media, or trigger blockchain-related actions, so an agent or caller that invokes the raw CLI directly can bypass the safety invariant and cause unintended irreversible changes.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This workflow performs a state-changing blockchain action immediately by calling `sendTransaction` after obtaining the encoded transaction, with no built-in preview-only mode or confirmation gate in this function. In the skill context, the metadata explicitly requires every state-changing flow to show an execution preview first and wait for confirmation, so this code path can cause unintended token creation if invoked by an agent or tool chain without an external safeguard.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill explicitly requires a private-key environment variable and describes networked API/transaction behavior, but it does not declare any tool scope such as allowed tools or permissions. That omission weakens reviewability and least-privilege controls, making it harder to constrain environment and network access for a highly sensitive workflow.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
General:

- Use `chainName`; do not ask users for chain IDs.
- Use `slug` as the main identifier for existing drops.
- Resolve backend identifiers internally.
- Do not ask for hidden backend IDs when `slug` is enough.
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
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.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
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.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
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.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
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.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
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.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
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.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
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.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation states that the script may derive a wallet address from `ELEMENT_WALLET_PRIVATE_KEY` if `walletAddress` is omitted, but it does not prominently warn users that a private-key-backed identity may be used implicitly. In the context of a blockchain/NFT management skill, this is security-relevant because users may trigger wallet-associated operations under an unintended identity and underestimate the sensitivity of the environment variable.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding
The documentation instructs users to run `npx tsx` without pinning an exact package version, which can cause code to be fetched and executed from the registry at invocation time. In a skill that interacts with blockchain assets and may rely on wallet-related environment variables, this increases supply-chain risk because a compromised or unexpectedly updated package could execute arbitrary code in the user's environment.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding
The documentation instructs users to run `npx tsx` without pinning an exact package version, which can cause execution of whatever version npm resolves at runtime. If a malicious or compromised package version is published or dependency resolution is influenced, this can lead to unintended code execution on the operator's machine.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The file describes a state-changing `update-drop` command that can automatically continue into a publish flow when live settings or prereveal data are changed, yet the execute section presents the live command without an explicit hard stop requiring prior preview review and user confirmation. In a skill that modifies NFT drop configuration and may trigger onchain-affecting publication, this omission materially increases the chance of unintended live changes, financial loss, or irreversible release of incorrect metadata or sale settings.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
This code reads a local image file, packages its bytes into multipart form data, and sends it via HTTP POST to `input.url`. Although the code logs failed responses, there is no confirmation prompt or user-facing disclosure in this file that local file contents will be uploaded to an external service.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The error logger records the full request URL and a recursively summarized response body to stderr, with only length truncation and no redaction of secrets or sensitive business data. In a skill that handles NFT drop configuration, external APIs may return presigned URLs, auth-related metadata, wallet-linked information, or unpublished drop details, which could then be exposed in logs accessible to operators or downstream log systems.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The postJson helper accepts arbitrary input and sends it over the network via fetch after JSON serialization. In this file there is no visible warning, confirmation, or explanatory comment indicating that caller-provided data will be transmitted externally, which matters for a reusable HTTP utility that may handle sensitive user or system data.

Static analysis

No suspicious patterns detected.