T09 · Insecure Skill Coding Practices
- Location
scripts/02-lock-btc-collateral.js:79- Finding
BTC collateral can be transferred twice when broadcast state is not persisted
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill appears to run the advertised BTCD collateral workflow, but it handles real private keys and mainnet funds with weak state, secret, and transaction-safety controls.
Install only after reviewing the scripts and using wallets funded with the minimum necessary amount. Do not reuse high-value private keys in the .env file, avoid shared/CI environments, confirm all transaction destinations and amounts manually, and treat reruns or setup resets as dangerous until state handling is fixed. The concerns found warrant Review rather than an outright malicious classification because the core behavior is disclosed and purpose-aligned, but the safety controls are not strong enough for unattended mainnet use.
scripts/02-lock-btc-collateral.js:79BTC collateral can be transferred twice when broadcast state is not persisted
scripts/setup.js:27Setup unconditionally overwrites transaction replay-protection state
scripts/utils/proof-generator.js:153Loan claim preimage is logged and stored in plaintext with default permissions
scripts/utils/state-manager.js:9User-controlled state filenames permit directory traversal and arbitrary JSON-file access
scripts/package.json:16Dependency installation is not reproducible because no lockfile or exact versions are provided
scripts/06-repay-loan.js:122Repayment signing falls back to an unverified BTC output
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).
automated:
state/flow-state.json first. If a btcTxId already exists, it resumes confirmation waiting instead of sending new BTC.confirmations >= 3), it skips entirely.Safe to re-run if interrupted — it will never double-send BTC.
npm run 03-submit-proof
Generates ZKP proof from the BTC transaction and submits to the EVM order contract.
Skip 04-arbiter-fee — not needed.
npm run 05-claim-btcd
Calls borrow() with the preImage from Step 2. BTCD tokens are minted to your EVM wallet.
npm run 06-repay
Calculates repayment (principal + interest), approves BTCD, signs the BTC repayment transaction, and calls repay().
**DO N
The skill reportedly supports arbitrary state-file reads/writes, archiving, and caller-influenced state-file selection, which goes beyond the declared workflow and can become dangerous if filenames or paths are attacker-controlled. In an agent setting, hidden filesystem flexibility can enable overwriting files, reading unintended state, or manipulating execution flow via crafted state inputs.
The skill reportedly supports arbitrary state-file reads/writes, archiving, and caller-influenced state-file selection, which goes beyond the declared workflow and can become dangerous if filenames or paths are attacker-controlled. In an agent setting, hidden filesystem flexibility can enable overwriting files, reading unintended state, or manipulating execution flow via crafted state inputs.
The skill reportedly supports arbitrary state-file reads/writes, archiving, and caller-influenced state-file selection, which goes beyond the declared workflow and can become dangerous if filenames or paths are attacker-controlled. In an agent setting, hidden filesystem flexibility can enable overwriting files, reading unintended state, or manipulating execution flow via crafted state inputs.
The skill reportedly supports arbitrary state-file reads/writes, archiving, and caller-influenced state-file selection, which goes beyond the declared workflow and can become dangerous if filenames or paths are attacker-controlled. In an agent setting, hidden filesystem flexibility can enable overwriting files, reading unintended state, or manipulating execution flow via crafted state inputs.
The skill instructs users to place both EVM and BTC private keys into a local .env file for use by bundled automation scripts. This is dangerous because plaintext secret storage materially increases the risk of credential theft through local compromise, accidental logging, shell history mishandling, backups, or other tooling that reads environment files.
.env from the template. Only two values need changing:
cp .env.template.txt .env
.env and set:
EVM_PRIVATE_KEY — your EVM private key (with 0x prefix)The ABI includes destructive operational methods like frozenArbitrator and terminateArbitratorWithSlash, as well as release/working-state controls, which are highly sensitive and not justified by the declared end-user purpose of creating or managing BTCD loans. If an agent has access to these methods and a sufficiently privileged signer, a malicious prompt, compromised workflow, or operator mistake could freeze or slash arbitrators and disrupt protocol operations or destroy economic value.
The ABI includes direct asset-withdrawal functions like withdrawETH and withdrawToken, enabling transfer of native currency or tokens to arbitrary recipients if the caller has sufficient privileges or if surrounding tooling signs such calls. Because the skill is presented as a collateralization/loan-flow assistant rather than an admin treasury tool, these capabilities are especially dangerous: a prompt-injected or confused agent could facilitate unauthorized asset exfiltration.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Load .env file from the test-flow directory
dotenv.config({ path: join(__dirname, '..', '.env') });
export const config = {
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Load .env file from the test-flow directory
dotenv.config({ path: join(__dirname, '..', '.env') });
export const config = {
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const __dirname = dirname(__filename);
// Load .env file from the test-flow directory
dotenv.config({ path: join(__dirname, '..', '.env') });
export const config = {
evm: {
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const __dirname = dirname(__filename);
// Load .env file from the test-flow directory
dotenv.config({ path: join(__dirname, '..', '.env') });
export const config = {
evm: {
This function logs the raw 32-byte preimage and its hash, exposing a secret that is typically intended to authorize or unlock value in hash/preimage-based flows. In a BTCD collateralization and proof-generation context, disclosure of the preimage through logs can let anyone with log access redeem, claim, front-run, or otherwise interfere with the protocol step that relies on secrecy, especially because automation logs are often shipped to centralized observability systems or shared with operators.
The comment explicitly states the environment-variable override exists so 'attack scripts' can use a separate state file, which is inconsistent with the declared BTCD collateralization purpose. While comments do not execute, they document intentional support for offensive or deceptive use cases, increasing the likelihood that the surrounding state-redirection capability was added to facilitate misuse or stealthy alternate execution paths.
The loadStateFrom documentation says it is used by 'attack scripts' to read original state while writing to a different file, describing a mechanism for shadow-state operation. In the context of a financial BTCD loan/collateralization skill, that can enable covert manipulation, replay, or evasion of normal workflow tracking by separating observed state from modified state.
The skill instructs the operator to handle private keys and run code that can access environment variables, but it declares no explicit tool scope or permission boundaries. In a high-risk blockchain automation skill, the absence of clear allowed-tools/permissions increases the chance that an agent executes sensitive actions or accesses secrets without adequate guardrails.
The trigger condition is broad: it activates for a wide set of requests involving loans, order creation, BTC locking, proofs, claims, and repayment. For a skill that can sign transactions and move funds across Bitcoin and EVM environments, ambiguous activation boundaries increase the risk of accidental invocation for high-consequence actions.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
| URL | Notes |
|-----|-------|
| `https://api.elastos.io/pg` | Primary (default) |
| `https://api2.elastos.io/pg` | Backup |
| `https://pgp-node.elastos.io` | Alternative |
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Agent must set their own EVM_PRIVATE_KEY and BTC_PRIVATE_KEY
EVM_PRIVATE_KEY=<AGENT_EVM_PRIVATE_KEY>
EVM_RPC_URL=https://api.elastos.io/pg
BTC_PRIVATE_KEY=<AGENT_BTC_PRIVATE_KEY_NO_0x_PREFIX>
BTC_NETWORK=mainnet
The ABI exposes numerous privileged governance and arbitrator-administration functions such as ownership transfer, manager reconfiguration, pausing, whitelist updates, and role-setting that go well beyond an end-user BTCD loan or collateralization workflow. In a skill context, bundling these capabilities increases the chance the agent could invoke high-privilege operations if prompted, misconfigured, or connected to a signer with elevated permissions, expanding the attack surface unnecessarily.
The ABI exposes privileged administrative functions such as changing operator, stablecoin, and loan contract addresses, as well as ownership transfer and withdrawal methods that are not aligned with the skill's stated user-facing purpose of running a BTCD collateralization flow. In an agent-skill context, exposing these methods increases the chance the agent could be induced or misconfigured to invoke sensitive contract-management actions, leading to fund loss or protocol reconfiguration outside user expectations.
The ABI exposed by the skill includes privileged administrative methods such as ownership transfer, factory/tool updates, timing changes, and interest receiver changes that go beyond the declared end-user BTCD loan-flow purpose. In an agent skill context, exposing these calls materially increases the chance that the agent could be induced to perform dangerous protocol-administration actions against a live contract, potentially redirecting funds, changing trust dependencies, or breaking loan lifecycle guarantees.
The administration-oriented ABI surface is not justified by the skill metadata, which describes operational loan actions rather than governance or contract management. In practice, this mismatch enables prompt-injection or misuse scenarios where an agent may be tricked into calling sensitive setters or ownership functions under the guise of normal loan execution, making the skill substantially more dangerous than advertised.
This JSON ABI exposes a nonpayable renounceOwnership function, which is an irreversible administrative action, but the file contains no comments, descriptions, or other user disclosure explaining that calling it can permanently remove owner privileges. For code/JSON interface artifacts, this qualifies as a missing warning when a safety-critical operation is present without any visible disclosure in the file.
The ABI includes transferOwnership(address newOwner), which changes administrative control and can materially affect system integrity, yet this file provides no visible warning, prompt, or explanatory text about that effect. Because the file is a manifest-style JSON artifact consumed by tools, the absence of any disclosure for this safety-critical operation is a quality/safety gap.
Detected: suspicious.env_credential_access