ton-vulnerability-scanner

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TON Vulnerability Scanner

TON漏洞扫描工具

1. Purpose

1. 用途

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.
系统性扫描TON区块链上使用FunC编写的智能合约,检测与布尔逻辑、Jetton代币处理及燃气管理相关的平台特定安全漏洞。本工具涵盖了3种TON架构特有的关键漏洞模式。

2. When to Use This Skill

2. 适用场景

  • Auditing TON smart contracts (FunC language)
  • Reviewing Jetton token implementations
  • Validating token transfer notification handlers
  • Pre-launch security assessment of TON dApps
  • Reviewing gas forwarding logic
  • Assessing boolean condition handling
  • 审计TON智能合约(FunC语言)
  • 审核Jetton代币实现方案
  • 验证代币转账通知处理逻辑
  • TON去中心化应用上线前的安全评估
  • 审核燃气转发逻辑
  • 评估布尔条件处理机制

3. Platform Detection

3. 平台检测

File Extensions & Indicators

文件扩展名与识别标识

  • FunC files:
    .fc
    ,
    .func
  • FunC文件
    .fc
    .func

Language/Framework Markers

语言/框架标记

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()
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 操作
op::transfer, op::transfer_notification
.store_uint().store_slice().store_coins()

Project Structure

项目结构

  • contracts/*.fc
    - FunC contract source
  • wrappers/*.ts
    - TypeScript wrappers
  • tests/*.spec.ts
    - Contract tests
  • ton.config.ts
    or
    wasm.config.ts
    - TON project config
  • contracts/*.fc
    - FunC合约源码
  • wrappers/*.ts
    - TypeScript包装器
  • tests/*.spec.ts
    - 合约测试用例
  • ton.config.ts
    wasm.config.ts
    - TON项目配置文件

Tool Support

工具支持

  • TON Blueprint: Development framework for TON
  • toncli: CLI tool for TON contracts
  • ton-compiler: FunC compiler
  • Manual review primarily (limited automated tools)

  • TON Blueprint:TON开发框架
  • toncli:TON合约CLI工具
  • ton-compiler:FunC编译器
  • 主要以人工审核为主(自动化工具有限)

4. How This Skill Works

4. 工作机制

When invoked, I will:
  1. Search your codebase for FunC/Tact contracts
  2. Analyze each contract for the 3 vulnerability patterns
  3. Report findings with file references and severity
  4. Provide fixes for each identified issue
  5. Check replay protection and sender validation

调用本工具后,我会:
  1. 搜索代码库中的FunC/Tact合约
  2. 分析每份合约是否存在3种漏洞模式
  3. 输出检测结果,包含文件引用和漏洞严重等级
  4. 提供修复方案针对每个发现的问题
  5. 检查重放保护和发送方验证机制

5. Example Output

5. 输出示例

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


---
当检测到漏洞时,你会收到如下格式的报告:
=== TON漏洞扫描结果 ===

项目:my-ton-contract
扫描文件数:3个(.fc、.tact)
发现漏洞数:2个

---

[CRITICAL] 缺失重放保护
文件:contracts/wallet.fc:45
模式:未验证序列号或随机数


---

5. Vulnerability Patterns (3 Patterns)

5. 漏洞模式(3种)

I check for 3 critical vulnerability patterns unique to TON. For detailed detection patterns, code examples, mitigations, and testing strategies, see VULNERABILITY_PATTERNS.md.
我会检查TON特有的3种关键漏洞模式。如需详细的检测模式、代码示例、修复方案和测试策略,请查看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.
  1. 缺失发送方校验 ⚠️ 严重 - 特权操作未验证发送方
  2. 整数溢出 ⚠️ 严重 - FunC中存在未校验的算术操作
  3. 燃气处理不当 ⚠️ 高风险 - 燃气预留不足
如需包含代码示例的完整漏洞模式说明,请查看VULNERABILITY_PATTERNS.md

5. Scanning Workflow

5. 扫描流程

Step 1: Platform Identification

步骤1:平台识别

  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
  1. 验证FunC语言(
    .fc
    .func
    文件)
  2. 检查是否为TON Blueprint或toncli项目结构
  3. 定位合约源码文件
  4. 识别与Jetton相关的合约

Step 2: Boolean Logic Review

步骤2:布尔逻辑审核

bash
undefined
bash
undefined

Find boolean-like variables

查找类布尔变量

rg "int.*is_|int.*has_|int.*flag|int.*enabled" contracts/
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"
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:
- [ ] Uses -1 for true, 0 for false
- [ ] NOT using 1 or other positive integers
- [ ] Logic operations work correctly
rg ".*(| " contracts/

针对每个布尔值:
- [ ] 使用-1表示真,0表示假
- [ ] 未使用1或其他正整数
- [ ] 逻辑运算正常工作

Step 3: Jetton Handler Analysis

步骤3:Jetton处理函数分析

bash
undefined
bash
undefined

Find transfer_notification handlers

查找transfer_notification处理函数

rg "transfer_notification|op::transfer_notification" contracts/

For each Jetton handler:
- [ ] Validates sender address
- [ ] Sender checked against stored Jetton wallet address
- [ ] Cannot trust forward_payload without sender validation
- [ ] Has admin function to set Jetton wallet address
rg "transfer_notification|op::transfer_notification" contracts/

针对每个Jetton处理函数:
- [ ] 验证发送方地址
- [ ] 发送方与存储的Jetton钱包地址匹配
- [ ] 未在未验证发送方的情况下信任forward_payload
- [ ] 存在设置Jetton钱包地址的管理员函数

Step 4: Gas/Forward Amount Review

步骤4:燃气/转账金额审核

bash
undefined
bash
undefined

Find forward amount usage

查找转账金额使用情况

rg "forward_ton_amount|forward_amount" contracts/ rg "load_coins()" contracts/
rg "forward_ton_amount|forward_amount" contracts/ rg "load_coins()" contracts/

Find send_raw_message calls

查找send_raw_message调用

rg "send_raw_message" contracts/

For each outgoing message:
- [ ] Forward amounts are fixed/bounded
- [ ] OR user-provided amounts validated against msg_value
- [ ] Cannot drain contract balance
- [ ] Appropriate send_raw_message flags used
rg "send_raw_message" contracts/

针对每个外发消息:
- [ ] 转账金额为固定值/有上限
- [ ] 或用户提供的金额已验证:`msg_value >= tx_fee + forward_amount`
- [ ] 合约余额不会被耗尽
- [ ] 使用了合适的send_raw_message标记

Step 5: Manual Review

步骤5:人工审核

TON contracts require thorough manual review:
  • Boolean logic with
    ~
    ,
    &
    ,
    |
    operators
  • Message parsing and validation
  • Gas economics and fee calculations
  • Storage operations and data serialization

TON合约需要全面的人工审核:
  • 使用
    ~
    &
    |
    运算符的布尔逻辑
  • 消息解析与验证
  • 燃气经济性与费用计算
  • 存储操作与数据序列化

6. Reporting Format

6. 报告格式

Finding Template

漏洞发现模板

markdown
undefined
markdown
undefined

[CRITICAL] Fake Jetton Contract - Missing Sender Validation

[CRITICAL] 伪造Jetton合约 - 缺失发送方校验

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:
  1. Attacker deploys malicious contract
  2. Malicious contract sends
    transfer_notification
    message to staking contract
  3. Message claims attacker transferred 1,000,000 Jettons
  4. Staking contract credits attacker without checking sender
  5. Attacker can now withdraw from contract or gain benefits without depositing
Proof of Concept:
typescript
// 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:
func
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

---
位置
contracts/staking.fc:85-95
(recv_internal,transfer_notification处理函数)
描述:
transfer_notification
操作处理函数未验证发送方是否为预期的Jetton钱包合约。攻击者可发送伪造的
transfer_notification
消息,声称已转账代币,无需实际存入Jetton即可给自己增加额度。
漏洞代码:
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);
}
攻击场景:
  1. 攻击者部署恶意合约
  2. 恶意合约向质押合约发送
    transfer_notification
    消息
  3. 消息声称攻击者已转账1,000,000个Jetton
  4. 质押合约未检查发送方就给攻击者增加额度
  5. 攻击者无需存入代币即可从合约提取资金或获取权益
概念验证:
typescript
// 攻击者发送伪造的transfer_notification
const attackerContract = await blockchain.treasury("attacker");

await stakingContract.sendInternalMessage(attackerContract.getSender(), {
  op: OP_CODES.TRANSFER_NOTIFICATION,
  jettonAmount: toNano("1000000"), // 伪造金额
  fromUser: attackerContract.address,
});

// 攻击者成功获得额度,无需发送真实Jetton
const balance = await stakingContract.getUserBalance(attackerContract.address);
expect(balance).toEqual(toNano("1000000")); // 攻击成功
修复建议: 存储预期的Jetton钱包地址并验证发送方:
func
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);
    }
}
参考:
  • building-secure-contracts/not-so-smart-contracts/ton/fake_jetton_contract

---

7. Priority Guidelines

7. 优先级指南

Critical (Immediate Fix Required)

严重(需立即修复)

  • Fake Jetton contract (unauthorized minting/crediting)
  • 伪造Jetton合约(未授权铸造/增加额度)

High (Fix Before Launch)

高风险(上线前修复)

  • Integer as boolean (logic errors, broken conditions)
  • Forward TON without gas check (balance drainage)

  • 整数当作布尔值使用(逻辑错误、条件失效)
  • 未做燃气检查的TON转账(余额耗尽)

8. Testing Recommendations

8. 测试建议

Unit Tests

单元测试

typescript
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,
    });
  });
});
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("应验证转账金额的燃气", async () => {
    const result = await contract.send(
      user.getSender(),
      { value: toNano("0.01") }, // 燃气不足
      {
        $$type: "Transfer",
        to: recipient.address,
        forward_ton_amount: toNano("1"), // 尝试转账1个TON
      }
    );

    expect(result.transactions).toHaveTransaction({
      success: false,
    });
  });
});

Integration Tests

集成测试

typescript
// 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,
  });
});

typescript
// 使用真实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,
  });
});

9. Additional Resources

9. 额外资源



10. Quick Reference Checklist

10. 快速参考检查清单

Before completing TON contract audit:
Boolean Logic (HIGH):
  • All boolean values use -1 (true) and 0 (false)
  • NO positive integers (1, 2, etc.) used as booleans
  • Functions returning booleans return -1 for true
  • Boolean logic with
    ~
    ,
    &
    ,
    |
    uses correct values
  • Tests verify boolean operations work correctly
Jetton Security (CRITICAL):
  • transfer_notification
    handler validates sender address
  • Sender checked against stored Jetton wallet address
  • Jetton wallet address stored during initialization
  • Admin function to set/update Jetton wallet
  • Cannot trust forward_payload without sender validation
  • Tests with fake Jetton contracts verify rejection
Gas & Forward Amounts (HIGH):
  • Forward TON amounts are fixed/bounded
  • OR user-provided amounts validated:
    msg_value >= tx_fee + forward_amount
  • Contract balance protected from drainage
  • Appropriate
    send_raw_message
    flags used
  • Tests verify cannot drain contract with excessive forward amounts
Testing:
  • Unit tests for all three vulnerability types
  • Integration tests with real Jetton contracts
  • Gas cost analysis for all operations
  • Testnet deployment before mainnet
完成TON合约审计前需检查:
布尔逻辑(高风险):
  • 所有布尔值使用-1(真)和0(假)
  • 未使用正整数(1、2等)当作布尔值
  • 返回布尔值的函数使用-1表示真
  • 使用
    ~
    &
    |
    的布尔逻辑使用正确的值
  • 测试验证布尔运算正常工作
Jetton安全(严重):
  • transfer_notification
    处理函数验证发送方地址
  • 发送方与存储的Jetton钱包地址匹配
  • Jetton钱包地址在初始化时存储
  • 存在设置/更新Jetton钱包的管理员函数
  • 未在未验证发送方的情况下信任forward_payload
  • 使用伪造Jetton合约的测试验证了拒绝逻辑
燃气与转账金额(高风险):
  • TON转账金额为固定值/有上限
  • 或用户提供的金额已验证:
    msg_value >= tx_fee + forward_amount
  • 合约余额不会被耗尽
  • 使用了合适的
    send_raw_message
    标记
  • 测试验证无法通过超额转账耗尽合约余额
测试:
  • 针对3种漏洞类型的单元测试
  • 使用真实Jetton合约的集成测试
  • 所有操作的燃气成本分析
  • 主网上线前部署到测试网