ton-vulnerability-scanner by trailofbits/skills
npx skills add https://github.com/trailofbits/skills --skill ton-vulnerability-scanner系统性地扫描 TON 区块链上使用 FunC 编写的智能合约,查找与布尔逻辑、Jetton 代币处理和 gas 管理相关的平台特定安全漏洞。此技能编码了 3 种 TON 架构特有的关键漏洞模式。
.fc, .func;; FunC 合约标识符
#include "imports/stdlib.fc";
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
;; 合约逻辑
}
() recv_external(slice in_msg) impure {
;; 外部消息处理器
}
;; 常见模式
send_raw_message()
load_uint(), load_msg_addr(), load_coins()
begin_cell(), end_cell(), store_*()
transfer_notification operation
op::transfer, op::transfer_notification
.store_uint().store_slice().store_coins()
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
contracts/*.fc - FunC 合约源代码wrappers/*.ts - TypeScript 包装器tests/*.spec.ts - 合约测试ton.config.ts 或 wasm.config.ts - TON 项目配置调用时,我将:
当发现漏洞时,您将收到类似以下的报告:
=== TON 漏洞扫描结果 ===
项目:my-ton-contract
已扫描文件:3 (.fc, .tact)
发现的漏洞:2
---
[严重] 缺少重放保护
文件:contracts/wallet.fc:45
模式:无序列号或随机数验证
---
## 5. 漏洞模式(3 种模式)
我检查 3 种 TON 特有的关键漏洞模式。有关详细的检测模式、代码示例、缓解措施和测试策略,请参阅 [VULNERABILITY_PATTERNS.md](resources/VULNERABILITY_PATTERNS.md)。
### 模式摘要:
1. **缺少发送者检查** ⚠️ 严重 - 特权操作无发送者验证
2. **整数溢出** ⚠️ 严重 - FunC 中未检查的算术运算
3. **不当的 Gas 处理** ⚠️ 高 - Gas 预留不足
有关包含代码示例的完整漏洞模式,请参阅 [VULNERABILITY_PATTERNS.md](resources/VULNERABILITY_PATTERNS.md)。
## 5. 扫描工作流程
### 步骤 1:平台识别
1. 验证 FunC 语言(`.fc` 或 `.func` 文件)
2. 检查 TON Blueprint 或 toncli 项目结构
3. 定位合约源文件
4. 识别与 Jetton 相关的合约
### 步骤 2:布尔逻辑审查
```bash
# 查找布尔类型变量
rg "int.*is_|int.*has_|int.*flag|int.*enabled" contracts/
# 检查用作布尔值的正整数
rg "= 1;|return 1;" contracts/ | grep -E "is_|has_|flag|enabled|valid"
# 查找对布尔类型值的 NOT 操作
rg "~.*\(|~ " contracts/
对于每个布尔值:
# 查找 transfer_notification 处理器
rg "transfer_notification|op::transfer_notification" contracts/
对于每个 Jetton 处理器:
# 查找 forward amount 的使用
rg "forward_ton_amount|forward_amount" contracts/
rg "load_coins\(\)" contracts/
# 查找 send_raw_message 调用
rg "send_raw_message" contracts/
对于每个外发消息:
TON 合约需要彻底的手动审查:
~、&、| 运算符的布尔逻辑## [严重] 虚假 Jetton 合约 - 缺少发送者验证
**位置**:`contracts/staking.fc:85-95` (recv_internal, transfer_notification 处理器)
**描述**:
`transfer_notification` 操作处理器未验证发送者是否为预期的 Jetton 钱包合约。任何攻击者都可以发送虚假的 `transfer_notification` 消息,声称已转账代币,从而在没有实际存入任何 Jettons 的情况下为自己增加信用。
**易受攻击的代码**:
```func
// staking.fc, 第 85 行
if (op == op::transfer_notification) {
int jetton_amount = in_msg_body~load_coins();
slice from_user = in_msg_body~load_msg_addr();
;; 错误:未验证 sender_address!
;; 攻击者可以声称任何 jetton_amount
credit_user(from_user, jetton_amount);
}
攻击场景:
transfer_notification 消息概念验证:
// 攻击者发送虚假的 transfer_notification
const attackerContract = await blockchain.treasury("attacker");
await stakingContract.sendInternalMessage(attackerContract.getSender(), {
op: OP_CODES.TRANSFER_NOTIFICATION,
jettonAmount: toNano("1000000"), // 虚假金额
fromUser: attackerContract.address,
});
// 攻击者成功获得信用,无需发送真实的 Jettons
const balance = await stakingContract.getUserBalance(attackerContract.address);
expect(balance).toEqual(toNano("1000000")); // 攻击成功
建议:存储预期的 Jetton 钱包地址并验证发送者:
global slice jetton_wallet_address;
() recv_internal(...) impure {
load_data(); ;; 从存储中加载 jetton_wallet_address
slice cs = in_msg_full.begin_parse();
int flags = cs~load_uint(4);
slice sender_address = cs~load_msg_addr();
int op = in_msg_body~load_uint(32);
if (op == op::transfer_notification) {
;; 关键:验证发送者
throw_unless(error::wrong_jetton_wallet,
equal_slices(sender_address, jetton_wallet_address));
int jetton_amount = in_msg_body~load_coins();
slice from_user = in_msg_body~load_msg_addr();
;; 可以安全地为用户增加信用
credit_user(from_user, jetton_amount);
}
}
参考资料:
---
## 7. 优先级指南
### 严重(需要立即修复)
* 虚假 Jetton 合约(未经授权的铸造/信用增加)
### 高(上线前修复)
* 整数作为布尔值(逻辑错误,条件判断失效)
* 转发 TON 时未检查 gas(余额耗尽)
---
## 8. 测试建议
### 单元测试
```typescript
import { Blockchain } from "@ton/sandbox";
import { toNano } from "ton-core";
describe("安全测试", () => {
let blockchain: Blockchain;
let contract: Contract;
beforeEach(async () => {
blockchain = await Blockchain.create();
contract = blockchain.openContract(await Contract.fromInit());
});
it("应使用正确的布尔值", async () => {
// 测试 TRUE = -1, FALSE = 0
const result = await contract.getFlag();
expect(result).toEqual(-1n); // 真
expect(result).not.toEqual(1n); // 不是 1!
});
it("应拒绝虚假的 jetton 转账", async () => {
const attacker = await blockchain.treasury("attacker");
const result = await contract.send(
attacker.getSender(),
{ value: toNano("0.05") },
{
$$type: "TransferNotification",
query_id: 0n,
amount: toNano("1000"),
from: attacker.address,
}
);
expect(result.transactions).toHaveTransaction({
success: false, // 应拒绝
});
});
it("应验证转发金额的 gas", async () => {
const result = await contract.send(
user.getSender(),
{ value: toNano("0.01") }, // Gas 不足
{
$$type: "Transfer",
to: recipient.address,
forward_ton_amount: toNano("1"), // 试图转发 1 TON
}
);
expect(result.transactions).toHaveTransaction({
success: false,
});
});
});
// 使用真实的 Jetton 钱包进行测试
it("应接受来自真实 jetton 钱包的转账", async () => {
// 部署实际的 Jetton 铸造器和钱包
const jettonMinter = await blockchain.openContract(JettonMinter.create());
const userJettonWallet = await jettonMinter.getWalletAddress(user.address);
// 在合约中设置 jetton 钱包
await contract.setJettonWallet(userJettonWallet);
// 来自 Jetton 钱包的真实转账
const result = await userJettonWallet.sendTransfer(
user.getSender(),
contract.address,
toNano("100"),
{}
);
expect(result.transactions).toHaveTransaction({
to: contract.address,
success: true,
});
});
building-secure-contracts/not-so-smart-contracts/ton/完成 TON 合约审计前:
布尔逻辑(高):
~、&、| 的布尔逻辑使用正确的值Jetton 安全(严重):
transfer_notification 处理器验证发送者地址Gas 和转发金额(高):
msg_value >= tx_fee + forward_amountsend_raw_message 标志测试:
每周安装量
1.1K
仓库
GitHub 星标数
3.9K
首次出现
Jan 19, 2026
安全审计
安装于
claude-code958
opencode914
gemini-cli900
codex892
cursor873
github-copilot841
Systematically scan TON blockchain smart contracts written in FunC for platform-specific security vulnerabilities related to boolean logic, Jetton token handling, and gas management. This skill encodes 3 critical vulnerability patterns unique to TON's architecture.
.fc, .func;; FunC contract indicators
#include "imports/stdlib.fc";
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
;; Contract logic
}
() recv_external(slice in_msg) impure {
;; External message handler
}
;; Common patterns
send_raw_message()
load_uint(), load_msg_addr(), load_coins()
begin_cell(), end_cell(), store_*()
transfer_notification operation
op::transfer, op::transfer_notification
.store_uint().store_slice().store_coins()
contracts/*.fc - FunC contract sourcewrappers/*.ts - TypeScript wrapperstests/*.spec.ts - Contract testston.config.ts or wasm.config.ts - TON project configWhen invoked, I will:
When vulnerabilities are found, you'll get a report like this:
=== TON VULNERABILITY SCAN RESULTS ===
Project: my-ton-contract
Files Scanned: 3 (.fc, .tact)
Vulnerabilities Found: 2
---
[CRITICAL] Missing Replay Protection
File: contracts/wallet.fc:45
Pattern: No sequence number or nonce validation
---
## 5. Vulnerability Patterns (3 Patterns)
I check for 3 critical vulnerability patterns unique to TON. For detailed detection patterns, code examples, mitigations, and testing strategies, see [VULNERABILITY_PATTERNS.md](resources/VULNERABILITY_PATTERNS.md).
### Pattern Summary:
1. **Missing Sender Check** ⚠️ CRITICAL - No sender validation on privileged operations
2. **Integer Overflow** ⚠️ CRITICAL - Unchecked arithmetic in FunC
3. **Improper Gas Handling** ⚠️ HIGH - Insufficient gas reservations
For complete vulnerability patterns with code examples, see [VULNERABILITY_PATTERNS.md](resources/VULNERABILITY_PATTERNS.md).
## 5. Scanning Workflow
### Step 1: Platform Identification
1. Verify FunC language (`.fc` or `.func` files)
2. Check for TON Blueprint or toncli project structure
3. Locate contract source files
4. Identify Jetton-related contracts
### Step 2: Boolean Logic Review
```bash
# Find boolean-like variables
rg "int.*is_|int.*has_|int.*flag|int.*enabled" contracts/
# Check for positive integers used as booleans
rg "= 1;|return 1;" contracts/ | grep -E "is_|has_|flag|enabled|valid"
# Look for NOT operations on boolean-like values
rg "~.*\(|~ " contracts/
For each boolean:
# Find transfer_notification handlers
rg "transfer_notification|op::transfer_notification" contracts/
For each Jetton handler:
# Find forward amount usage
rg "forward_ton_amount|forward_amount" contracts/
rg "load_coins\(\)" contracts/
# Find send_raw_message calls
rg "send_raw_message" contracts/
For each outgoing message:
TON contracts require thorough manual review:
~, &, | operators## [CRITICAL] Fake Jetton Contract - Missing Sender Validation
**Location**: `contracts/staking.fc:85-95` (recv_internal, transfer_notification handler)
**Description**:
The `transfer_notification` operation handler does not validate that the sender is the expected Jetton wallet contract. Any attacker can send a fake `transfer_notification` message claiming to have transferred tokens, crediting themselves without actually depositing any Jettons.
**Vulnerable Code**:
```func
// staking.fc, line 85
if (op == op::transfer_notification) {
int jetton_amount = in_msg_body~load_coins();
slice from_user = in_msg_body~load_msg_addr();
;; WRONG: No validation of sender_address!
;; Attacker can claim any jetton_amount
credit_user(from_user, jetton_amount);
}
Attack Scenario :
transfer_notification message to staking contractProof of Concept :
// Attacker sends fake transfer_notification
const attackerContract = await blockchain.treasury("attacker");
await stakingContract.sendInternalMessage(attackerContract.getSender(), {
op: OP_CODES.TRANSFER_NOTIFICATION,
jettonAmount: toNano("1000000"), // Fake amount
fromUser: attackerContract.address,
});
// Attacker successfully credited without sending real Jettons
const balance = await stakingContract.getUserBalance(attackerContract.address);
expect(balance).toEqual(toNano("1000000")); // Attack succeeded
Recommendation : Store expected Jetton wallet address and validate sender:
global slice jetton_wallet_address;
() recv_internal(...) impure {
load_data(); ;; Load jetton_wallet_address from storage
slice cs = in_msg_full.begin_parse();
int flags = cs~load_uint(4);
slice sender_address = cs~load_msg_addr();
int op = in_msg_body~load_uint(32);
if (op == op::transfer_notification) {
;; CRITICAL: Validate sender
throw_unless(error::wrong_jetton_wallet,
equal_slices(sender_address, jetton_wallet_address));
int jetton_amount = in_msg_body~load_coins();
slice from_user = in_msg_body~load_msg_addr();
;; Safe to credit user
credit_user(from_user, jetton_amount);
}
}
References :
building-secure-contracts/not-so-smart-contracts/ton/fake_jetton_contract
import { Blockchain } from "@ton/sandbox";
import { toNano } from "ton-core";
describe("Security tests", () => {
let blockchain: Blockchain;
let contract: Contract;
beforeEach(async () => {
blockchain = await Blockchain.create();
contract = blockchain.openContract(await Contract.fromInit());
});
it("should use correct boolean values", async () => {
// Test that TRUE = -1, FALSE = 0
const result = await contract.getFlag();
expect(result).toEqual(-1n); // True
expect(result).not.toEqual(1n); // Not 1!
});
it("should reject fake jetton transfer", async () => {
const attacker = await blockchain.treasury("attacker");
const result = await contract.send(
attacker.getSender(),
{ value: toNano("0.05") },
{
$$type: "TransferNotification",
query_id: 0n,
amount: toNano("1000"),
from: attacker.address,
}
);
expect(result.transactions).toHaveTransaction({
success: false, // Should reject
});
});
it("should validate gas for forward amount", async () => {
const result = await contract.send(
user.getSender(),
{ value: toNano("0.01") }, // Insufficient gas
{
$$type: "Transfer",
to: recipient.address,
forward_ton_amount: toNano("1"), // Trying to forward 1 TON
}
);
expect(result.transactions).toHaveTransaction({
success: false,
});
});
});
// Test with real Jetton wallet
it("should accept transfer from real jetton wallet", async () => {
// Deploy actual Jetton minter and wallet
const jettonMinter = await blockchain.openContract(JettonMinter.create());
const userJettonWallet = await jettonMinter.getWalletAddress(user.address);
// Set jetton wallet in contract
await contract.setJettonWallet(userJettonWallet);
// Real transfer from Jetton wallet
const result = await userJettonWallet.sendTransfer(
user.getSender(),
contract.address,
toNano("100"),
{}
);
expect(result.transactions).toHaveTransaction({
to: contract.address,
success: true,
});
});
building-secure-contracts/not-so-smart-contracts/ton/Before completing TON contract audit:
Boolean Logic (HIGH) :
~, &, | uses correct valuesJetton Security (CRITICAL) :
transfer_notification handler validates sender addressGas & Forward Amounts (HIGH):
msg_value >= tx_fee + forward_amountsend_raw_message flags usedTesting :
Weekly Installs
1.1K
Repository
GitHub Stars
3.9K
First Seen
Jan 19, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
claude-code958
opencode914
gemini-cli900
codex892
cursor873
github-copilot841
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装
NestJS专家服务 | 企业级TypeScript后端开发与架构设计
1,000 周安装
安全代码卫士:AI驱动的安全编码指南与最佳实践,防止SQL注入、XSS攻击
1,000 周安装
ESLint迁移到Oxlint完整指南:JavaScript/TypeScript项目性能优化工具
1,000 周安装
Chrome CDP 命令行工具:轻量级浏览器自动化,支持截图、执行JS、无障碍快照
1,000 周安装
Sanity内容建模最佳实践:结构化内容设计原则与无头CMS指南
1,000 周安装
AI Sprint规划器 - 敏捷团队Scrum迭代计划工具,自动估算故事点与容量管理
1,000 周安装