ton-vulnerability-scanner — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ton-vulnerability-scanner (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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 Reviewrg "int.is_|int.has_|int.flag|int.enabled" contracts/
rg "= 1;|return 1;" contracts/ | grep -E "is_|has_|flag|enabled|valid"
rg "~.*\(|~ " contracts/
For each boolean:
- [ ] Uses -1 for true, 0 for false
- [ ] NOT using 1 or other positive integers
- [ ] Logic operations work correctly
### Step 3: Jetton Handler Analysisrg "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
### Step 4: Gas/Forward Amount Reviewrg "forward_ton_amount|forward_amount" contracts/ rg "load_coins\(\)" contracts/
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
### Step 5: Manual Review
TON contracts require thorough manual review:
- Boolean logic with `~`, `&`, `|` operators
- Message parsing and validation
- Gas economics and fee calculations
- Storage operations and data serialization
---
## 6. Reporting Format
### Finding TemplateLocation: 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:
// 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 succeededRecommendation: 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:
---
## 7. Priority Guidelines
### Critical (Immediate Fix Required)
- Fake Jetton contract (unauthorized minting/crediting)
### High (Fix Before Launch)
- Integer as boolean (logic errors, broken conditions)
- Forward TON without gas check (balance drainage)
---
## 8. Testing Recommendations
### Unit Testsimport { 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, }); }); });
### Integration Tests// 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, }); });
---
## 9. Additional Resources
- **Building Secure Contracts**: `building-secure-contracts/not-so-smart-contracts/ton/`
- **TON Documentation**: https://docs.ton.org/
- **FunC Documentation**: https://docs.ton.org/develop/func/overview
- **TON Blueprint**: https://github.com/ton-org/blueprint
- **Jetton Standard**: https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md
---
## 10. Quick Reference Checklist
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~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.