Back to skill

Security audit

Kaspa Dev

Security checks for vulnerabilities and agentic risk

Overview

This Kaspa development skill is purpose-related but contains unsafe wallet, transaction, dependency, and node-operation guidance that could put funds or systems at risk if followed directly.

Review carefully before installing or using. Treat the included scripts and examples as unsafe for real funds unless revised: do not print or save private keys or mnemonics in plaintext, do not rely on the Python transaction builder for signing or submission, test only on testnet/devnet first, pin and verify all packages/images/binaries, and bind node RPC to localhost unless you have explicit authenticated remote-access controls.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (9)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate-address.py:255
Finding
Wallet private keys and mnemonic phrases are exposed through plaintext output and files<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate-address.py:255-300`; related examples in `SKILL.md:30-37` and `references/kaspa-python-sdk.md:212-217, 572-582` **Vulnerability Type**: Plaintext disclosure and insecure storage of wallet secrets **Risk Level**: High ### Vulnerable Code ```python for i in range(args.count): address, wif, private_key = generator.generate_address(compressed) result = { 'index': i + 1, 'address': address, 'private_key_wif': wif, 'private_key_hex': private_key.hex(), 'network': args.network, 'compressed': compressed } results.append(result) if args.format == 'text': print(f"Address {i + 1}:") print(f" Address: {address}") print(f" Private Key: {wif}") print(f" Hex: {private_key.hex()}") print() if args.output: if args.format == 'json': import json with open(args.output, 'w') as f: json.dump(results, f, indent=2) elif args.format == 'csv': import csv with open(args.output, 'w', newline='') as f: writer = csv.DictWriter(f, fieldnames=results[0].keys()) writer.writeheader() writer.writerows(results) else: with open(args.output, 'w') as f: for result in results: f.write(f"Address: {result['address']}\n") f.write(f"Private Key: {result['private_key_wif']}\n") f.write(f"Hex: {result['private_key_hex']}\n") f.write("\n") print(" These keys are generated locally and are not stored anywhere.") ``` The documentation also encourages secret logging: ```javascript console.log('Private Key:', privateKey.toString()); ``` ```python print(f"Private Key: {private_key.hex()}") print(f"Mnemonic: {' '.join(mnemonic)}") ``` ### Technical Analysis A WIF private key, raw private key, or mnemonic phrase provides complete control o ...[truncated 1508 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not display private keys or mnemonics by default. Require an explicit, strongly worded opt-in for secret export. - Prefer encrypted wallet files or integration with an operating-system key store or hardware wallet. - If plaintext export is unavoidable, create the file atomically with mode `0600`, reject existing files, and verify permissions after creation. - Never print both WIF and raw hexadecimal forms. - Warn users that terminal output and files may be retained by logs and backups. - Remove the inaccurate “not stored anywhere” statement when an output file is used. - Replace documentation examples that print private keys or mnemonic phrases with examples that print only public addresses. - Clear or minimize the lifetime of secret-containing objects where supported by the SDK. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/build-transaction.py:420
Finding
Transaction submission accepts private-key presence as proof of signing while returning an unsigned transaction<![CDATA[ ## Vulnerability Details **File Location**: `scripts/build-transaction.py:420-438, 539-546` **Vulnerability Type**: Missing cryptographic signing and invalid authorization-state validation **Risk Level**: High ### Vulnerable Code ```python def _sign_transaction( self, transaction: Transaction, private_key_wif: str ) -> Transaction: """Sign a transaction with a private key. Note: This is a placeholder. Real signing requires: 1. secp256k1 library for ECDSA signatures 2. Proper sighash calculation 3. Schnorr signature support (Kaspa uses Schnorr) For production use, use the official SDKs or a proper signing library. """ print("WARNING: Transaction signing not fully implemented in this script.") print("Please use official Kaspa SDKs for production signing:") print(" - JavaScript: kaspa-wasm") print(" - Rust: kaspa-wallet-core") print(" - Go: github.com/kaspanet/kaspad") # Return unsigned transaction return transaction ``` Submission nevertheless relies only on whether the argument was supplied: ```python if args.submit: if not args.private_key: print("\nError: Cannot submit unsigned transaction. Provide --private-key") sys.exit(1) print("\nSubmitting transaction...") tx_id = rpc.submit_transaction(transaction.to_dict()) print(f"Transaction submitted! ID: {tx_id}") ``` ### Technical Analysis `_sign_transaction()` does not parse or use the supplied WIF, calculate a signature hash, create a Schnorr signature, or populate any input's `signatureScript`. It explicitly returns the unchanged unsigned transaction. The submission gate checks only that `args.private_key` is non-empty. It therefore conflates possession of a string with successful cryptographic signing. This violates the transaction builder's stated behavior and creates an unsafe authorization state in which unsigned data is represented as ready for broadcast. ### Attack Path 1. A user in ...[truncated 870 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove or disable `--submit` until complete Kaspa Schnorr signing is implemented. - Use an official Kaspa SDK rather than implementing consensus-sensitive signing manually. - Parse and validate the WIF, verify that it corresponds to the sender address, and reject mismatches. - Calculate the correct signature hash using each spent UTXO's amount and script data. - Populate and verify every input signature before allowing submission. - Add a dedicated `is_fully_signed()` check that validates all inputs cryptographically rather than testing argument presence. - Add official signed-transaction test vectors and negative tests for missing, malformed, or mismatched keys. - Return a hard error from the placeholder instead of returning an unsigned transaction. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/build-transaction.py:209
Finding
Fee is excluded from UTXO selection, allowing invalid transactions or unintended excessive fees<![CDATA[ ## Vulnerability Details **File Location**: `scripts/build-transaction.py:209-247`; equivalent documentation example at `references/kaspa-python-sdk.md:329-381` **Vulnerability Type**: Unsafe transaction arithmetic and insufficient-funds validation **Risk Level**: High ### Vulnerable Code ```python # Select UTXOs selected_utxos, total_input = self._select_utxos(utxos, amount) if total_input < amount: raise ValueError( f"Insufficient funds. Have: {total_input}, Need: {amount}" ) # Get fee estimate if fee_rate is None: fee_estimate = self.rpc.get_fee_estimate() fee_rate = fee_estimate["normalBucket"]["feeRate"] # Calculate fee (simplified estimation) estimated_size = 200 + len(selected_utxos) * 150 + 35 fee = fee_rate * estimated_size # Create recipient output recipient_script = self._address_to_script(recipient_address) outputs = [ TransactionOutput( amount=amount, script_public_key=ScriptPublicKey( version=0, script=recipient_script ) ) ] # Add change output if needed change = total_input - amount - fee if change > self.DUST_THRESHOLD: sender_script = self._address_to_script(sender_address) outputs.append( TransactionOutput( amount=change, script_public_key=ScriptPublicKey( version=0, script=sender_script ) ) ) ``` ### Technical Analysis UTXOs are selected only until `total_input >= amount`. The fee is calculated afterward, and the code never verifies that `total_input >= amount + fee`. If the selected value covers the payment but not the payment plus fee, `change` becomes negative. Python permits the negative arithmetic, and the condition suppresses the change output. Once real signing is added, the effective transaction fee becomes the entire difference between all inputs and outputs, rather than the intended estimate. If the difference is insufficient under consensus ...[truncated 1033 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Select UTXOs against `amount + fee`, not only `amount`. - Use an iterative transaction-building process because adding inputs and change outputs changes transaction mass and fees. - Reject the operation unless `total_input >= amount + final_fee`. - Enforce checked, non-negative arithmetic for all amounts. - Add a user-configurable absolute and percentage-based maximum fee. - Validate remote fee estimates against local minimum and maximum policy bounds. - Use the official SDK's mass and fee calculation instead of a simplified byte-size approximation. - Add tests for exact-balance wallets, high fee rates, dust change, multiple inputs, and malicious fee estimates. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
references/kaspa-go-sdk.md:420
Finding
Go transaction example can underflow change and signs against an unrelated output index<![CDATA[ ## Vulnerability Details **File Location**: `references/kaspa-go-sdk.md:420-473, 511-538` **Vulnerability Type**: Unsigned integer underflow and incorrect signature-hash input data **Risk Level**: High ### Vulnerable Code ```go // Calculate fee estimatedSize := uint64(200 + len(selectedUtxos)*150 + 35) fee := feeEstimate.NormalBucket.FeeRate * estimatedSize // Create outputs recipientScript, err := txscript.PayToAddrScript(recipientAddress) if err != nil { return nil, err } outputs := []*externalapi.DomainTransactionOutput{ { Value: amount, ScriptPublicKey: recipientScript, }, } // Add change output change := totalInput - amount - fee if change > 546 { senderScript, err := txscript.PayToAddrScript(senderAddress) if err != nil { return nil, err } outputs = append(outputs, &externalapi.DomainTransactionOutput{ Value: change, ScriptPublicKey: senderScript, }) } ``` The signing example then indexes the new transaction's outputs using the spent outpoint index: ```go func signTransaction(tx *externalapi.DomainTransaction, privateKey *btcec.PrivateKey) (*externalapi.DomainTransaction, error) { for i := range tx.Inputs { // Calculate signature hash sighash, err := txscript.CalcSignatureHash( tx.Outputs[tx.Inputs[i].PreviousOutpoint.Index].ScriptPublicKey, txscript.SigHashAll, tx, i, ) if err != nil { return nil, err } signature, err := privateKey.Sign(sighash[:]) if err != nil { return nil, err } sigScript, err := txscript.NewScriptBuilder(). AddData(append(signature.Serialize(), byte(txscript.SigHashAll))). AddData(privateKey.PubKey().SerializeCompressed()). Script() if err != nil { return nil, err } tx.Inputs[i].SignatureScript = sigScri ...[truncated 1584 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Use checked arithmetic and reject transactions when `totalInput < amount + fee`. - Recalculate the final fee after input and output selection. - Retain the full previous-output data for each input, including amount and script public key. - Calculate each signature hash using the corresponding spent UTXO, not an index into the new outputs. - Use the official Kaspa transaction signing helpers instead of custom signing code. - Validate all array indices before access and avoid panics in externally reachable services. - Add tests for high outpoint indices, multiple UTXOs, exact balances, fee underflow, and signatures verified by a Kaspa node. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
references/node-operations.md:82
Finding
Recommended node configurations expose the RPC service on all network interfaces<![CDATA[ ## Vulnerability Details **File Location**: `references/node-operations.md:82-112`; repeated at lines `139-178, 247-277, 327-364` **Vulnerability Type**: Excessive network exposure and insecure default access control **Risk Level**: High ### Vulnerable Code ```bash docker run -d \ --name kaspad \ -p 16110:16110 \ -p 16111:16111 \ -v kaspad-data:/data \ kaspanet/kaspad:latest \ --utxoindex \ --rpclisten=0.0.0.0:16110 ``` The recommended Compose configuration uses the same default: ```yaml services: kaspad: image: kaspanet/kaspad:latest container_name: kaspad restart: unless-stopped ports: - "16110:16110" # RPC - "16111:16111" # P2P volumes: - kaspad-data:/data command: > kaspad --utxoindex --rpclisten=0.0.0.0:16110 --listen=0.0.0.0:16111 --acceptance-index ``` The persistent service similarly exposes RPC: ```ini ExecStart=/usr/local/bin/kaspad --utxoindex --rpclisten=0.0.0.0:16110 --listen=0.0.0.0:16111 --acceptance-index ``` ### Technical Analysis Binding RPC to `0.0.0.0` makes it reachable through every host interface. Publishing Docker port `16110` exposes it beyond the container as well. The primary examples omit RPC authentication, TLS, reverse-proxy controls, and source-IP restrictions. Although the guide later warns about external RPC access and includes firewall examples, users following the basic or “recommended” configurations receive an insecure default. RPC access is not necessary from arbitrary remote hosts for normal local node operation, so this exceeds minimum required exposure. ### Attack Path 1. A user copies the basic Docker, recommended Compose, or systemd configuration. 2. Port 16110 becomes reachable from a local network or the internet, depending on host firewall and routing. 3. An attacker scans for the exposed Kaspa RPC endpoint. 4. The attacker invokes available RPC methods, performs expensive repeated queries, inspects node dat ...[truncated 610 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Bind RPC to `127.0.0.1:16110` by default. - Do not publish port 16110 from Docker unless remote access is explicitly required. - For Docker, use a loopback-only mapping such as `127.0.0.1:16110:16110`. - Require strong authentication and TLS for all remote RPC access. - Restrict remote access with firewall allowlists or a mutually authenticated reverse proxy. - Put secure defaults directly in the basic, Compose, monitoring, configuration-file, and systemd examples. - Keep P2P and RPC exposure separate; public P2P access does not require public RPC access. - Add rate limiting, connection limits, monitoring, and alerts for failed authentication or abusive query volume. ]]>

T08 · Insecure Dependencies

Error
Location
references/node-operations.md:213
Finding
Downloaded executables are installed with root privileges without checksum or signature verification<![CDATA[ ## Vulnerability Details **File Location**: `references/node-operations.md:213-221`; repeated in the upgrade procedure at lines `456-469` **Vulnerability Type**: Unverified executable supply chain **Risk Level**: High ### Vulnerable Code ```bash # Get latest release URL from https://github.com/kaspanet/kaspad/releases wget https://github.com/kaspanet/kaspad/releases/download/v0.12.18/kaspad-v0.12.18-linux-amd64.zip ``` ```bash unzip kaspad-v0.12.18-linux-amd64.zip sudo mv kaspad kaspactl kaspaminer /usr/local/bin/ sudo chmod +x /usr/local/bin/kasp* ``` The upgrade procedure repeats the behavior: ```bash wget https://github.com/kaspanet/kaspad/releases/download/vX.X.X/kaspad-vX.X.X-linux-amd64.zip sudo systemctl stop kaspad unzip kaspad-vX.X.X-linux-amd64.zip sudo mv kaspad kaspactl /usr/local/bin/ sudo systemctl start kaspad ``` ### Technical Analysis The URL points to the declared official `kaspanet` GitHub organization rather than a personal paste site. Nevertheless, the instructions do not verify a publisher signature, release attestation, or cryptographic checksum before moving the downloaded binaries into `/usr/local/bin`. The binary is later registered as a systemd service and enabled across boots. Consequently, compromise of the release account, artifact, repository, or distribution path could turn a supply-chain event into persistent local code execution. ### Attack Path 1. An upstream release account or artifact is compromised, or a user is redirected to a maliciously replaced artifact. 2. The user follows the guide and downloads the ZIP without independent integrity verification. 3. The archive is extracted, and its executables are moved into `/usr/local/bin` using `sudo`. 4. The binary is started and enabled as `kaspad.service`. 5. Malicious code executes on every service start with the permissions of the `kaspad` account and access to the node data directory. ### Impact Assessment Installation requires root privileges to replace ...[truncated 346 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Publish and verify SHA-256 or stronger checksums through an authenticated, independently verifiable channel. - Prefer signed releases and verify the publisher's signature or provenance attestation before extraction. - Abort installation immediately if verification fails. - Download into a newly created restricted temporary directory and inspect archive paths before extraction. - Pin an explicit, supported release version. - Avoid wildcard operations such as `chmod +x /usr/local/bin/kasp*`. - Verify ownership, expected filenames, and permissions before service startup. - Preserve a known-good binary and document a verified rollback procedure. ]]>

T08 · Insecure Dependencies

Warning
Location
references/node-operations.md:95
Finding
Mutable latest container tags permit unreviewed code changes in persistent services<![CDATA[ ## Vulnerability Details **File Location**: `references/node-operations.md:95-112`; additional instances at lines `139, 166, 183, 193` **Vulnerability Type**: Mutable container dependency references **Risk Level**: Medium ### Vulnerable Code ```yaml services: kaspad: image: kaspanet/kaspad:latest container_name: kaspad restart: unless-stopped ports: - "16110:16110" - "16111:16111" volumes: - kaspad-data:/data command: > kaspad --utxoindex --rpclisten=0.0.0.0:16110 --listen=0.0.0.0:16111 --acceptance-index ``` Other monitoring examples use: ```yaml image: prom/prometheus:latest image: grafana/grafana:latest ``` ### Technical Analysis The `latest` tag is mutable: it can resolve to different image content over time without any configuration change or code review. The services use `restart: unless-stopped`, and the guide recommends pulling updates with `docker-compose pull`, allowing newly resolved images to become persistent runtime components. A compromised registry account, malicious upstream publication, or unexpected breaking release can therefore alter executable behavior after the Skill itself has been audited. ### Attack Path 1. An attacker compromises an upstream image publisher or registry account. 2. The attacker moves the `latest` tag to a malicious image. 3. An operator runs the documented pull and restart procedure, or an automated updater fetches the tag. 4. The malicious image starts with access to published ports and mounted persistent volumes. 5. It can read or modify the corresponding service data and communicate over the network. ### Impact Assessment A malicious `kaspad` image would gain access to the node's mounted data and network interfaces. Compromised Prometheus or Grafana images could access their own persistent data, monitoring credentials, and reachable internal services. Container escape is not established, but host impact may increase if Dock ...[truncated 68 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin each image to a tested version and immutable digest, for example `image@sha256:<digest>`. - Maintain a controlled update process that reviews release notes and image provenance. - Enable container-signature or provenance verification where supported. - Scan images before deployment and retain a known-good digest for rollback. - Do not combine mutable tags with unattended update tools for wallet or node infrastructure. - Run containers as non-root, use read-only filesystems where possible, drop unnecessary capabilities, and restrict outbound connectivity. ]]>

T08 · Insecure Dependencies

Error
Location
references/kaspa-wasm-sdk.md:577
Finding
Wallet-sensitive browser code imports a mutable module directly from a third-party CDN<![CDATA[ ## Vulnerability Details **File Location**: `references/kaspa-wasm-sdk.md:577-583` **Vulnerability Type**: Mutable remote JavaScript dependency in a cryptographic context **Risk Level**: High ### Vulnerable Code ```html <script type="module"> import * as kaspa from 'https://unpkg.com/kaspa-wasm@latest/kaspa_wasm.js'; const privateKey = kaspa.PrivateKey.random(kaspa.NetworkType.Mainnet); console.log(privateKey.toPublicKey().toAddress(kaspa.NetworkType.Mainnet).toString()); </script> ``` ### Technical Analysis The browser fetches and executes JavaScript directly from `unpkg.com` at page load. The `@latest` selector is mutable, so the effective code can change without any modification to the application. The module is used in a context that creates private keys and may sign transactions. Native module imports do not provide an integrity attribute equivalent to a pinned Subresource Integrity hash in this form. Compromise of the NPM package, CDN, publisher account, or mutable release could therefore execute attacker-controlled JavaScript in the application's origin. ### Attack Path 1. The package publisher, NPM account, or CDN delivery path is compromised. 2. The `latest` version is changed to malicious JavaScript. 3. A user opens an application built from the documented example. 4. The browser downloads and executes the changed module with the page's privileges. 5. The module reads generated keys, changes recipient addresses, modifies transaction amounts, or exfiltrates signing material to an attacker-controlled server. ### Impact Assessment The injected module would execute in the wallet application's browser context. It could access keys handled by the page, alter transactions before signing, impersonate the user in message-signing flows, and steal all funds controlled by exposed keys. The impact is limited by browser-origin isolation but is critical within the affected application. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Install the package through a lockfile-controlled build process rather than importing it from a CDN at runtime. - Pin an exact audited package version and verify lockfile integrity in CI. - Bundle the module with the application and serve it from the application's own origin. - If CDN delivery is unavoidable, pin immutable content and use a delivery mechanism that supports cryptographic integrity verification. - Apply a restrictive Content Security Policy that disallows unapproved script and network destinations. - Audit package provenance and monitor for publisher or ownership changes. - Keep private-key creation and signing outside mutable third-party page code, preferably in a wallet extension or hardware wallet. ]]>

T08 · Insecure Dependencies

Warning
Location
references/kaspa-python-sdk.md:1
Finding
Unpinned unofficial Python package is recommended for wallet-related operations<![CDATA[ ## Vulnerability Details **File Location**: `references/kaspa-python-sdk.md:1-11`; dependency guidance at lines `641-647` **Vulnerability Type**: Unpinned community dependency and ambiguous package provenance **Risk Level**: Medium ### Vulnerable Code ```markdown # Kaspa Python SDK Python SDKs for Kaspa blockchain development. While there isn't an official Python implementation, several community libraries are available. ## Installation ### Option 1: kaspa-python (Community) ```bash pip install kaspa-python ``` ``` The dependency list uses broad lower bounds: ```txt requests>=2.28.0 bech32>=1.2.0 secp256k1>=0.14.0 ``` ### Technical Analysis The guide explicitly states that the Python implementation is unofficial but provides only a package name, without a verified publisher identity, source repository, exact version, or hash. The broad dependency constraints allow future releases to be installed without review. Wallet libraries process private keys, mnemonic seeds, addresses, and transactions. A malicious or compromised package can execute during installation or import and has direct access to these assets. No evidence establishes that the named package is currently malicious; the issue is the unsafe acquisition and pinning practice. ### Attack Path 1. A developer follows the guide and installs `kaspa-python` without confirming its publisher or source. 2. The package is compromised, transferred to a malicious maintainer, or replaced by a future malicious release. 3. `pip` resolves and installs the new release because no exact version or hash is required. 4. Package installation or import executes attacker-controlled code. 5. The code reads environment variables, wallet material, project files, or transaction data and sends them to an attacker. ### Impact Assessment The package executes with the developer or application account's privileges. It may read all files and environment secrets available to that account, alter generated addresses ...[truncated 190 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Identify the exact vetted package publisher and link its source repository and release process. - Pin an audited exact version rather than using an unconstrained install command. - Use `pip --require-hashes` with a reviewed requirements file. - Generate and verify a lockfile for all transitive dependencies. - Review package ownership, release signatures, source-to-wheel reproducibility, and recent maintainer changes. - Install into an isolated virtual environment without administrative privileges. - Prefer official Kaspa SDK bindings or a minimal locally reviewed API client for security-sensitive wallet operations. - Add dependency scanning and automated alerts, but require human review before upgrades. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (57)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The description substantially overstates the functionality present in the supplied code. The actual code is limited to a Python command-line utility for constructing simple Kaspa transfer transactions and KRC20 payload transactions using a hosted API for UTXO lookup, fee estimation, and submission. It does not provide the broad multi-language blockchain development toolkit described, nor wallet management, address generation, dApp/block explorer tooling, integration helpers, node setup, or SDK coverage. Most importantly, the script advertises building and signing transactions in comments/docstring, but its signing function is a placeholder that returns the transaction unsigned after printing warnings. While transaction building, KRC20 handling, and optional broadcast do align with a subset of the declared purpose, the overall description does not accurately represent this code chunk’s real scope or implemented capabilities.

Missing User Warnings

High
Confidence
99% confidence
Finding
The example prints the raw private key to stdout, which is a full wallet secret. Console output is commonly captured in shell history, logs, notebooks, CI systems, or screenshots; disclosure would let an attacker immediately take control of the associated funds.

Missing User Warnings

High
Confidence
99% confidence
Finding
The complete example prints the mnemonic phrase, which grants full recovery of the wallet and all derived accounts. In a blockchain SDK guide, users are likely to copy-paste and run examples verbatim; exposing the mnemonic to terminal output or logs creates immediate account-compromise risk.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The file header and usage text claim the script 'builds and signs' Kaspa transactions, but `_sign_transaction` is only a placeholder that emits warnings and returns the transaction unchanged. In a blockchain tooling context, this can mislead operators into believing a transaction has been signed and is ready for submission, causing failed transfers, broken automation, or unsafe downstream handling based on false assumptions about transaction state.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The submit path checks only for the presence of `--private-key` before calling `submit_transaction`, even though providing a private key does not actually sign the transaction in this script. This creates a dangerous trust boundary error: callers and automation may interpret private-key presence as proof of signing, leading to submission of invalid transactions and possible operational or financial disruption.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill documents behaviors that imply network access and file-writing related workflows, but it does not declare any explicit tool scope or permissions boundary. In an agent ecosystem, this can cause capability ambiguity: a caller may authorize or execute the skill with broader-than-expected privileges, increasing the chance of unintended network actions or file modifications.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill includes wallet/address generation and transaction broadcasting examples, including printing a private key and connecting to a mainnet RPC endpoint, without prominent warnings about secret handling, irreversible transfers, and real-funds risk. In a blockchain context, users may copy these examples directly into production or client-side environments, leading to key exposure, accidental fund loss, or unsafe signing flows.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The markdown describes submitting a signed transaction to the network, which can affect user funds and is generally irreversible once propagated, but it does not include any cautionary note. For markdown files, safety-relevant behavior that can affect user data or system integrity should be accompanied by a clear warning.

External Transmission

Medium
Category
Data Exfiltration
Content
# Get balance
def get_balance(address):
    response = requests.post(
        f'{BASE_URL}/api/v1/rpc/get-balance-by-address',
        json={'address': address},
        headers=HEADERS
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The example includes a complete mainnet fund-transfer flow, including UTXO selection, signing, and SubmitTransaction, but does not warn that copying it as-is can create and broadcast real transactions that move assets. In a developer skill focused on blockchain integration, users may paste examples directly into production code, so the absence of an explicit safety warning increases the chance of accidental mainnet transfers or unintended loss through testing mistakes.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The file exposes a direct transaction submission method without a prominent warning that broadcasting blockchain transactions can be irreversible and may transfer real funds. In this skill context, which is aimed at wallet and transaction development, omission of such warnings increases the chance of accidental mainnet broadcasts during experimentation.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The function signature and docstring imply the private key is used to build a usable transaction, but the code never signs inputs and leaves signature_script empty. In a blockchain-development skill, this is dangerous because developers may assume the output is ready for submission, causing failed transactions, unsafe downstream workarounds, or accidental integration of insecure signing logic.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The document presents a BIP39 mnemonic generator while explicitly using an incomplete word list, yet indexes it as though all 2048 entries exist. This can produce runtime errors or, worse, non-standard mnemonics that users may believe are valid backups, leading to irreversible wallet loss when funds are stored against keys derived from incompatible seed material.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The document includes wallet/private key handling and transaction construction examples without an explicit warning that private keys, mnemonics, WIFs, and signed transactions are highly sensitive and that broadcasting transactions can irreversibly transfer funds. In a blockchain development skill, users are likely to copy example code directly into real environments, which increases the chance of secret exposure or unintended mainnet transfers.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This markdown file includes a complete `sendKaspa` example that signs and submits a transaction to Mainnet, which can move real funds irreversibly. Although the file includes general best practices, it does not clearly warn users near the example that running it may broadcast a real transaction and spend assets.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The file includes instructions and an example for burning tokens, and explicitly states this will 'Permanently destroy tokens.' However, the documentation does not provide a clear cautionary warning to users about the irreversibility and risk of accidental loss when performing this operation. For markdown files, destructive behaviors affecting user assets should be accompanied by an explicit warning.

External Transmission

Medium
Category
Data Exfiltration
Content
"""Get KRC20 token balance for an address."""
    
    response = requests.get(
        f"https://api.kaspa.org/api/v1/addresses/{address}/tokens",
        headers={"Authorization": f"Bearer {api_key}"}
    )
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding
Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding
The Docker example uses `kaspanet/kaspad:latest`, a mutable tag that can silently change over time. This harms reproducibility and can cause operators to deploy an unexpected or compromised image if the upstream tag is replaced or updated.

Session Persistence

Medium
Category
Rogue Agent
Content
### Docker Compose (Recommended)

Create `docker-compose.yml`:

```yaml
version: '3.8'
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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
2. **Extract and install:**
```bash
unzip kaspad-v0.12.18-linux-amd64.zip
sudo mv kaspad kaspactl kaspaminer /usr/local/bin/
sudo chmod +x /usr/local/bin/kasp*
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
2. **Extract and install:**
```bash
unzip kaspad-v0.12.18-linux-amd64.zip
sudo mv kaspad kaspactl kaspaminer /usr/local/bin/
sudo chmod +x /usr/local/bin/kasp*
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
2. **Extract and install:**
```bash
unzip kaspad-v0.12.18-linux-amd64.zip
sudo mv kaspad kaspactl kaspaminer /usr/local/bin/
sudo chmod +x /usr/local/bin/kasp*
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
2. **Extract and install:**
```bash
unzip kaspad-v0.12.18-linux-amd64.zip
sudo mv kaspad kaspactl kaspaminer /usr/local/bin/
sudo chmod +x /usr/local/bin/kasp*
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
2. **Extract and install:**
```bash
unzip kaspad-v0.12.18-linux-amd64.zip
sudo mv kaspad kaspactl kaspaminer /usr/local/bin/
sudo chmod +x /usr/local/bin/kasp*
```
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

No suspicious patterns detected.