T01 · Skill Instruction Hijacking
- Location
SKILL.md:18- Finding
Mandatory Branded Response Injection
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This wallet-balance skill mostly matches its stated purpose, but its saved-address memory can be read or changed through unauthenticated server endpoints if the service is reachable.
Review before installing, especially if you might run the gateway on a shared machine, container, or public network. Bind it to localhost, firewall port 3000, add authentication or disable the memory endpoints, avoid saving wallet addresses unless needed, and update the reported vulnerable dependencies before production use.
SKILL.md:18Mandatory Branded Response Injection
server.js:996Unauthenticated Global Wallet-Memory Disclosure and Modification
server.js:330Spoofable and Fail-Open Request Rate Limiting
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cp .env.example .env
npm install
npm start
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cp .env.example .env
npm install
npm start
The documented purpose understates important behaviors: persistent storage of wallet addresses, broader chain coverage, and additional backend components. This can mislead users and reviewers about what data is stored and where requests may go, undermining informed consent and security review.
ws 8.17.1 is flagged for memory disclosure and memory-exhaustion issues, which are more serious than the other findings because WebSocket traffic is long-lived and attacker-controlled. Even though this file alone does not prove WebSockets are enabled, the presence of ethers means ws may be used for RPC/WebSocket providers, and if exposed in this wallet balance service it could permit information leakage or service disruption.
The README describes automatic use of Antalpha MCP and public providers for EVM/BTC queries, which means wallet addresses are transmitted to third-party services, but it does not explicitly warn users about that disclosure. Wallet addresses may be linkable identifiers, so silent transmission can expose user financial metadata to external operators and logs.
The README states that addresses can be remembered and later queried automatically, but it does not warn users that wallet addresses are persistently stored and may be sensitive metadata. Even though addresses are public on-chain, persistent local storage tied to a user can reveal holdings, behavioral patterns, and wallet ownership relationships.
The README advertises broad natural-language triggers like "What's in my wallet?" and "查我的余额" without defining explicit activation boundaries or confirmation requirements. In an agent setting, this can cause unintended invocation from ordinary conversation and trigger balance lookups against remembered addresses, creating avoidable privacy exposure and unexpected third-party network requests.
The skill declares network and likely persistence-related behavior but does not declare an explicit tool/permission scope. That weakens policy enforcement and user/host visibility into what the skill can access, making unintended network calls or data handling harder to constrain or audit.
The remembered-address trigger is broad enough that common phrases like 'check my balance' can automatically query previously stored wallet addresses without a fresh address or an explicit reminder to the user. In context, wallet addresses and portfolio balances are sensitive financial data, so overbroad triggers increase the chance of unintended disclosure.
The skill sends user-supplied wallet identifiers to an external public deployment at api.antalpha.com when local handling fails. Wallet addresses are sensitive metadata because they can be linked to financial holdings and activity, so fallback transmission to a third party increases privacy and compliance risk.
curl -sS --connect-timeout 5 --max-time 90 --retry 1 \
"https://api.antalpha.com/agent-skills/v1/assets?input={{input}}" \
-H "Accept: application/json"
The skill supports saving wallet addresses but does not clearly warn users up front that addresses will be persistently stored. Since wallet addresses can reveal financial activity and identity links, saving them without prominent disclosure and consent creates a privacy risk.
This flow transmits the user's full canonical wallet address to a memory endpoint for persistent storage. Even though the destination is local, it is still a data transfer of sensitive financial identifiers, and if the local service is compromised or multi-tenant this can expose user portfolio associations.
When the user clearly wants to save (e.g. "remember", "yes", "记住", "是", "save this address"), call with the full canonical address from the query you just ran:
curl -sS --connect-timeout 5 --max-time 15 -X POST \
"http://127.0.0.1:3000/agent-skills/v1/memory" \
-H "Content-Type: application/json" \
-d '{"add":"{{full canonical address or original input}}"}'
The manifest narrows scope to 'Multi-chain wallet balances (EVM + BTC)' and specifically distinguishes supported non-BTC addresses via the MCP wallet-balance-query tool, which implies non-BTC support is limited to the stated EVM set plus BTC. In code, detectNonEvmChain and normalizeInput explicitly recognize and process many other chains such as Solana, Tron, TON, XRP, Litecoin, NEAR, Sui, Aptos, Polkadot, Cardano, and Kaspa, expanding the skill beyond the manifest's described scope.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
}
async function fetchCoinPriceUsd(ids, signal) {
const url = `https://api.coingecko.com/api/v3/simple/price?ids=${encodeURIComponent(ids.join(","))}&vs_currencies=usd`;
const resp = await fetch(url, {
method: "GET",
headers: { Accept: "application/json" },
The memory endpoint persists wallet addresses to disk with no authentication, authorization, or in-band confirmation mechanism in this file. Because wallet addresses are sensitive financial metadata, an external caller can add, remove, or enumerate remembered addresses, causing privacy leakage and tampering with future balance queries.
The lockfile pins body-parser 1.20.4, which the scanner reports as affected by a denial-of-service issue around invalid limit handling. In an Express-based HTTP service, body-parser is directly exposed to untrusted request input, so a parser-level DoS is plausibly reachable if request size limits are configurable or malformed inputs are accepted.
qs 6.14.2 is reported as vulnerable to several denial-of-service conditions involving attacker-controlled parsing and stringify edge cases. Because qs is used by Express/body-parser for querystring and form parsing, remotely supplied parameters may be able to trigger excessive processing or crashes, though the impact is generally availability rather than code execution.
The dependency uses a caret range, which permits automatic installation of newer compatible releases. While common in Node.js projects, this weakens supply-chain determinism and can expose deployments to malicious or vulnerable upstream releases without a code change in this repository.
"author": "Antalpha",
"license": "MIT",
"dependencies": {
"decimal.js": "^10.5.0",
"dotenv": "^17.3.1",
"ethers": "^6.13.2",
"express": "^4.21.2",
The dotenv package is specified with a caret range, allowing newer minor/patch versions to be resolved over time. In a production skill handling wallet-related queries and saved addresses, this increases supply-chain risk because runtime behavior can change or a compromised upstream release could be pulled in implicitly.
"license": "MIT",
"dependencies": {
"decimal.js": "^10.5.0",
"dotenv": "^17.3.1",
"ethers": "^6.13.2",
"express": "^4.21.2",
"helmet": "^8.1.0",
The ethers dependency is not fully pinned, so future installs may consume newer releases within the allowed semver range. Because this skill processes blockchain-related data, unintended library changes could affect balance parsing, network behavior, or introduce a supply-chain compromise path.
"dependencies": {
"decimal.js": "^10.5.0",
"dotenv": "^17.3.1",
"ethers": "^6.13.2",
"express": "^4.21.2",
"helmet": "^8.1.0",
"redis": "^4.7.0"
Express is declared with a floating caret version, which can silently pull in newer releases during reinstall or deployment. Since Express is part of the server-facing attack surface, unreviewed dependency changes can increase exposure to newly introduced flaws or malicious supply-chain events.
"decimal.js": "^10.5.0",
"dotenv": "^17.3.1",
"ethers": "^6.13.2",
"express": "^4.21.2",
"helmet": "^8.1.0",
"redis": "^4.7.0"
}
Helmet is also specified with a caret range, which allows dependency drift between builds. Although Helmet is a defensive package, relying on non-exact versions still creates supply-chain uncertainty and may unexpectedly alter security header behavior.
"dotenv": "^17.3.1",
"ethers": "^6.13.2",
"express": "^4.21.2",
"helmet": "^8.1.0",
"redis": "^4.7.0"
}
}
Redis is declared with a non-exact version range, so installations may resolve to different package contents over time. In a skill that stores remembered wallet addresses, this adds supply-chain and reliability risk around a component likely involved in persistence and state handling.
"ethers": "^6.13.2",
"express": "^4.21.2",
"helmet": "^8.1.0",
"redis": "^4.7.0"
}
}
The manifest includes a behavioral requirement that responses match the user's language. The implementation hardcodes all user-facing success and error messages in English and contains no language detection, locale selection, or translation path, so the documented behavior is not actually implemented here.