Back to skill

Security audit

Blockchain Web3 Toolkit

Security checks for vulnerabilities and agentic risk

Overview

This is a real blockchain toolkit, but it handles wallet secrets and irreversible on-chain actions with too little protection for safe agent use.

Review carefully before installing. Do not use this with funded wallets or production mainnet accounts unless you add secret-storage protections, remove private-key printing and default serialization, pin dependencies, and require explicit user confirmation before any deploy, mint, transfer, or state-changing transaction.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/wallet_manager.py:30
Finding
Plaintext Private-Key Exposure Through Serialization and Console Output## Vulnerability Details **File Location**: `scripts/wallet_manager.py:30-34` **Additional Locations**: `README.md:27-32`, `scripts/wallet_manager.py:94-98`, `examples/basic_usage.py:20-24` **Vulnerability Type**: Plaintext handling and disclosure of wallet private keys **Risk Level**: High ### Vulnerable Code `scripts/wallet_manager.py:30-34`: ```python def to_dict(self) -> Dict: return { "address": self.address, "private_key": self.private_key } ``` `README.md:27-32`: ```python # Create a new wallet wallet = WalletManager.create_wallet() print(f"Address: {wallet.address}") print(f"Private Key: {wallet.private_key}") # Query balance ``` `scripts/wallet_manager.py:94-98`: ```python wallet = WalletManager.create_wallet() print(f"Address: {wallet.address}") print(f"Private Key: {wallet.private_key[:20]}...{wallet.private_key[-10:]}") # Validate address ``` `examples/basic_usage.py:20-24`: ```python print("\n[Step 1] Creating a new Ethereum wallet...") wallet = WalletManager.create_wallet() print(f"✓ Address: {wallet.address}") print(f"✓ Private Key: {wallet.private_key[:20]}...{wallet.private_key[-10:]}") print(" ⚠️ IMPORTANT: Save this private key securely!") ``` ### Technical Analysis `Wallet.to_dict()` places the complete private key into a normal dictionary without encryption, access controls, or an explicit secret-export operation. Such dictionaries can easily be serialized, logged, sent through telemetry, included in exception diagnostics, or persisted in plaintext. The documented quick-start example is more severe because it explicitly prints the complete private key. The executable examples also print private-key fragments. Although those fragments alone do not expose the entire key, they unnecessarily disclose secret material and encourage unsafe handling practices. Private keys are bearer credentials: possession of the full key is su ...[truncated 1452 chars]
Remediation
## Remediation Suggestions 1. Remove `private_key` from the default `to_dict()` output. Default serialization should contain only non-secret wallet metadata such as the public address. 2. Replace generic plaintext export with an explicitly named operation such as `export_encrypted_keystore(password)`. 3. Use the Ethereum encrypted keystore format and a strong, user-supplied password with an appropriate key-derivation function. 4. If encrypted keystores are written to disk, create files with restrictive owner-only permissions and avoid predictable temporary files. 5. Remove all complete and partial private-key output from the README, examples, tests, and command-line demonstrations. 6. Ensure object representations, logs, exceptions, telemetry, and debugging output redact secret values. 7. Add tests that verify private keys are absent from default serialization and console output. 8. Document secure backup procedures and advise users to rotate any wallet whose key may already have entered logs or plaintext storage.

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
Unpinned and Non-Reproducible Third-Party Dependency Installation## Vulnerability Details **File Location**: `requirements.txt:1-5` **Additional Location**: `README.md:17-21` **Vulnerability Type**: Mutable dependency resolution without integrity verification **Risk Level**: Medium ### Vulnerable Code `requirements.txt:1-5`: ```text web3>=6.0.0 eth-account>=0.8.0 cryptography>=3.4.8 python-dotenv>=0.19.0 requests>=2.28.0 ``` `README.md:17-21`: ```markdown ## Installation ```bash pip install -r requirements.txt ``` ``` ### Technical Analysis Every dependency uses an open-ended lower-bound constraint. A fresh installation can therefore select versions that did not exist when the project was audited, along with a changing set of transitive dependencies. No lockfile, exact version constraints, or package hashes are supplied to establish the expected dependency contents. Python packages can execute code during installation and import. If a permitted future release or one of its transitive dependencies is compromised, the documented installation process may introduce attacker-controlled code into the user's environment. The unused direct dependency `requests` also increases the dependency and transitive supply-chain surface without providing observed project functionality. This issue does not establish that any currently named package is malicious. The risk arises because the project cannot reproduce or verify the dependency set that was reviewed. ### Attack Path 1. A user runs the documented `pip install -r requirements.txt` command. 2. The package resolver selects the latest versions satisfying the open-ended constraints and resolves their current transitive dependencies. 3. A compromised, malicious, or unexpectedly changed future package release is selected because no reviewed version or cryptographic hash is required. 4. Package-controlled code executes during installation or when imported by the toolkit. 5. That code runs with the installing user's privi ...[truncated 668 chars]
Remediation
## Remediation Suggestions 1. Pin every direct dependency to an exact reviewed version rather than using unrestricted lower bounds. 2. Generate a lockfile or compiled requirements file that also fixes all transitive dependency versions. 3. Record and verify package hashes, and install with pip's `--require-hashes` option where practical. 4. Remove `requests` unless it is required by actual project functionality. 5. Perform dependency updates through a controlled review process with vulnerability scanning, changelog review, and automated tests. 6. Use a trusted package index configuration and prevent fallback to unapproved indexes. 7. Run installation and application execution in isolated, least-privilege environments without unrelated wallet secrets or production credentials.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (26)

Missing User Warnings

High
Confidence
95% confidence
Finding
The quick-start example prints a newly created wallet's private key directly to stdout, normalizing unsafe handling of a secret that grants full control over on-chain assets. In documentation for a blockchain toolkit, users may copy this pattern into scripts, terminals, logs, notebooks, or screenshots, causing irreversible compromise if the key is exposed.

Missing User Warnings

High
Confidence
98% confidence
Finding
The example prints private key material directly to stdout, even if partially masked. Console output is commonly captured by terminals, shell history tools, CI logs, screen recordings, and remote session logging, so exposing any secret-derived value in example code normalizes unsafe handling and can lead to credential compromise if copied into real workflows.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README documents contract deployment and transaction-sending capabilities without warning that blockchain transactions are irreversible, may incur real financial cost, and can affect live mainnet assets. In the context of a Web3 toolkit aimed at developers and users, omission of these warnings increases the chance of accidental loss through misuse, testing on mainnet, or unintended contract interactions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill advertises high-risk blockchain capabilities, including wallet management, smart contract deployment, NFT minting/transfers, and gas monitoring, but provides no warning about irreversible transactions, private key sensitivity, financial loss, or the need for explicit confirmation. In this context, the omission is more dangerous because users may treat routine-looking commands as safe even though mistakes can permanently transfer assets, expose credentials, or deploy faulty contracts on-chain.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger list is broad enough to match common crypto-related discussion rather than clearly scoped operational requests, which can cause the skill to activate in contexts where the user did not intend wallet, contract, or token-related actions. In a blockchain skill, accidental invocation is especially risky because the described capabilities involve sensitive and potentially irreversible operations such as wallet management, contract deployment, and NFT transfers.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Contract deployment creates, signs, and submits a real on-chain transaction without any safety disclosure or approval checkpoint, potentially consuming significant funds and deploying unreviewed bytecode permanently. In a skill/agent setting this is especially risky because deployment is a high-impact action that may be triggered programmatically from untrusted or misunderstood inputs.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This method signs and broadcasts state-changing blockchain transactions immediately, with no confirmation flow, simulation, or warning that the action is irreversible and may spend funds. In an agent skill context, that is more dangerous because upstream prompts or automation could trigger real on-chain effects without the operator fully understanding the consequences.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The method directly exposes a state-changing mint operation and forwards parameters to a transaction-sending interface without any built-in confirmation, policy check, or guardrail. In an agent skill context, this increases the risk of unintended on-chain asset creation if an upstream prompt, user mistake, or compromised workflow triggers the function.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The transfer helper performs a state-changing NFT transfer with no local confirmation step, no recipient validation, and no friction before sending the transaction. In an agent-driven environment this is especially dangerous because a mistaken or manipulated instruction could irreversibly transfer valuable NFTs to an attacker-controlled address.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The Wallet object stores and exposes the raw private key as a normal string and includes it in serialization via to_dict(), making accidental logging, persistence, transmission, or memory disclosure far more likely. In a wallet-management context this is especially dangerous because compromise of the private key directly enables theft of all assets controlled by the address.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The mnemonic import path accepts highly sensitive seed phrases and immediately derives a wallet without any safety controls, warnings, or isolation, increasing the chance that a recovery phrase is pasted into an unsafe environment, logged, or retained in process memory. Because a mnemonic can recover an entire wallet hierarchy, exposure can lead to complete compromise of multiple accounts, not just one key.

Natural-Language Policy Violations

Low
Confidence
79% confidence
Finding
The file includes a bilingual docstring title, but all user-facing runtime messages are hardcoded in English. This can violate a language/locale policy when a skill imposes a single language without user opt-in or documented justification.

Unpinned Dependencies

Low
Category
Supply Chain
Content
web3>=6.0.0
eth-account>=0.8.0
cryptography>=3.4.8
python-dotenv>=0.19.0
Confidence
96% confidence
Finding
The dependency specification uses a lower-bound version only, which permits installation of many future releases with unknown security properties and behavior. In a security-sensitive stack that includes blockchain, cryptography, and HTTP libraries, this weakens build reproducibility and can unintentionally introduce vulnerable or breaking versions.

Unverifiable Dependency: web3 has 2 known advisory(ies) (CVE-2026-40072 (web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling); CVE-2026-40072 (web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
The manifest does not pin web3, so it is impossible to verify whether the deployed version is affected by known advisories such as SSRF-related issues in web3.py. In a blockchain-integrated skill, this uncertainty is more dangerous because web3 often processes untrusted on-chain or off-chain lookup data and may make outbound requests.

Unpinned Dependencies

Low
Category
Supply Chain
Content
web3>=6.0.0
eth-account>=0.8.0
cryptography>=3.4.8
python-dotenv>=0.19.0
requests>=2.28.0
Confidence
96% confidence
Finding
The eth-account package is unpinned and may resolve to different versions across environments or over time. Because this library handles account and signing functionality, unpredictable upgrades can expose the skill to known bugs or security regressions without any code change.

Unverifiable Dependency: eth-account has 2 known advisory(ies) (CVE-2022-1930 (Regular expression denial of service in eth-account); CVE-2022-1930 (Regular expression denial of service in eth-account)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
87% confidence
Finding
Because eth-account is not pinned, the installed version may or may not include fixes for known issues such as ReDoS. This creates avoidable uncertainty in a package that may process attacker-influenced inputs during wallet or account-related operations.

Unpinned Dependencies

Low
Category
Supply Chain
Content
web3>=6.0.0
eth-account>=0.8.0
cryptography>=3.4.8
python-dotenv>=0.19.0
requests>=2.28.0
Confidence
98% confidence
Finding
An unpinned cryptography dependency is riskier than a typical utility library because it underpins core security functions. Allowing arbitrary newer versions can pull in releases affected by crypto flaws, packaging issues, or incompatible OpenSSL builds, undermining trust in encryption and signing operations.

Unverifiable Dependency: cryptography has 16 known advisory(ies) (GHSA-39hc-v87j-747x (Vulnerable OpenSSL included in cryptography wheels); CVE-2023-50782 (Python Cryptography package vulnerable to Bleichenbacher timing oracle attack); GHSA-537c-gmf6-5ccf (Vulnerable OpenSSL included in cryptography wheels) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding
Cryptography has a substantial advisory history, and the lack of pinning means the runtime could silently resolve to an affected build or wheel. Since this library is central to cryptographic correctness and transport security, version uncertainty materially increases the chance of serious compromise.

Unpinned Dependencies

Low
Category
Supply Chain
Content
web3>=6.0.0
eth-account>=0.8.0
cryptography>=3.4.8
python-dotenv>=0.19.0
requests>=2.28.0
Confidence
92% confidence
Finding
Using python-dotenv with only a minimum version reduces reproducibility and can permit installation of releases with undiscovered or known issues. While this package is usually auxiliary, it can affect secret loading and file handling behavior in ways that matter for operational security.

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
84% confidence
Finding
The unpinned python-dotenv dependency prevents confirmation that the installed release is free from known file-handling issues. If the skill uses dotenv features to write or manage environment files, a vulnerable version could contribute to local file overwrite or secret-management risks.

Unpinned Dependencies

Low
Category
Supply Chain
Content
eth-account>=0.8.0
cryptography>=3.4.8
python-dotenv>=0.19.0
requests>=2.28.0
Confidence
97% confidence
Finding
Requests is a network-facing library, and leaving it unpinned can expose the application to future vulnerable releases or inconsistent behavior between deployments. Because HTTP client bugs can lead to credential leakage, SSRF-adjacent issues, or TLS handling problems, deterministic version control is important.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding
Requests has multiple historical advisories, and because the version is not pinned, there is no assurance the installed build includes the necessary fixes. This is especially relevant in any agent skill that performs outbound HTTP requests, where URL parsing, credential handling, and TLS behavior directly affect security.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
abi=abi
        )
        
        func = getattr(contract.functions, function_name)
        return func(*args).call()
    
    def send_transaction(self, contract_address: str, abi: list, function_name: str, *args) -> str:
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Content
abi=abi
        )
        
        func = getattr(contract.functions, function_name)
        return func(*args).call()
    
    def send_transaction(self, contract_address: str, abi: list, function_name: str, *args) -> str:
Confidence
50% confidence
Finding
Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The file title and several docstrings present content bilingually, but the skill does not indicate any user language preference or opt-in mechanism. This can violate a language/locale policy where the skill should not impose a language format without user choice.

Static analysis

No suspicious patterns detected.