Back to skill

Security audit

Sui Sec

Security checks for vulnerabilities and agentic risk

Overview

This Sui transaction guardrail claims broad protection but only implements a narrow spending check, which could let unsafe transactions be labeled safe.

Review before installing or relying on this skill. It may be useful only as a limited dry-run helper, not as an authoritative transaction security gate. Do not let it automatically approve signing or execution without independent review of recipients, all asset movements, object ownership changes, call targets, and simulation output.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
main.py:52
Finding
Caller-Controlled Owner Address Bypasses Transaction Loss Detection<![CDATA[ ## Vulnerability Details **File Location**: `main.py:52-57, 96-111` **Vulnerability Type**: Fail-open transaction validation caused by trusting caller-controlled identity data **Risk Level**: High ### Vulnerable Code ```python for change in balance_changes: if (change.get("owner") == owner_addr or change.get("owner", {}).get("AddressOwner") == owner_addr) \ and change.get("coinType") == "0x2::sui::SUI": amount = int(change.get("amount", 0)) if amount < 0: actual_sui_loss += abs(amount) / 1e9 ``` ```python def main(): if len(sys.argv) < 4: print("Usage: python3 main.py '<ptb_command>' <intended_cost> <owner_address>") sys.exit(1) raw_cmd = sys.argv[1] intended_cost = float(sys.argv[2]) owner_addr = sys.argv[3] # 1. Execute secure simulation raw_output = run_simulation(raw_cmd) # 2. Parse JSON (filtering out potential ASCII warning text from Sui CLI) try: json_start = raw_output.find('{') if json_start == -1: raise ValueError("No JSON found") json_data = json.loads(raw_output[json_start:]) # 3. Perform the audit audit_balance_changes(json_data, intended_cost, owner_addr) ``` ### Technical Analysis The auditor calculates SUI loss only for the address supplied through the `owner_address` command-line argument. It does not derive the transaction sender from authoritative Sui simulation output or verify that the supplied address is the signer. This contradicts the documented claim in `SKILL.md` that the tool detects the sender from simulation output. If an unrelated address is supplied, none of the actual sender's negative balance changes match `owner_addr`. Consequently, `actual_sui_loss` remains zero and the transaction can receive a `SAFE TO SIGN` verdict. The issue is fail-open because the absence of matching balance records is interpreted as zero expenditure rather than an invalid or ambiguous sender. ### Attack Pa ...[truncated 988 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Derive the sender from authoritative transaction or simulation data rather than accepting it as an untrusted argument. - Verify that the derived sender matches the active Sui client address and intended signer. - Treat missing, malformed, ambiguous, or mismatched sender information as a blocking audit failure. - Require at least one validated sender balance record when evaluating a transaction that can incur gas or asset expenditure. - If an owner argument must remain available, use it only as an expected value and compare it against the independently derived sender. - Add tests proving that unrelated, absent, and malformed owner addresses cannot produce `SAFE TO SIGN`. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
main.py:61
Finding
Object Ownership Hijack Detection Is Unimplemented<![CDATA[ ## Vulnerability Details **File Location**: `main.py:61-72, 84-90` **Vulnerability Type**: Missing security-control implementation leading to false-safe verdicts **Risk Level**: High ### Vulnerable Code ```python # 2. Detect object ownership changes (HIJACK) # Check if objects originally owned by the user are transferred to others in objectChanges object_changes = json_data.get("objectChanges", []) hijacked_objects = [] for obj in object_changes: if obj.get("type") == "mutated": # Simple logic: If an object was user-held but is now transferred to a non-user address (e.g., 0xdeadbeef) # This section can be expanded based on actual simulation data pass ``` ```python # Criteria: Actual expenditure should not exceed intended cost (plus a 0.02 Gas buffer) if actual_sui_loss > (intended_cost + 0.02): print(f"🚨 [RESULT] ❌ MALICIOUS: Price mismatch detected!") print(f" Hidden drain of {actual_sui_loss - intended_cost:.4f} SUI.") sys.exit(1) else: print(f"✅ [RESULT] SAFE TO SIGN.") ``` ### Technical Analysis The code creates a `hijacked_objects` list but never populates or evaluates it. The loop handling mutated objects contains only `pass`. Created, transferred, deleted, wrapped, published, and other object-change types are also not checked. The final decision depends exclusively on native SUI expenditure. Therefore, an unexpected ownership change involving an NFT, capability object, token object, profile, or other Sui object does not affect the verdict. This is particularly dangerous because `SKILL.md` represents object hijacking as an automatically detected threat and treats the script's exit code as authoritative. The discrepancy can lead downstream agents to trust a control that does not exist. ### Attack Path 1. An attacker constructs a PTB that transfers or otherwise diverts a user-owned object to an attacker-controlled address. 2. The transaction keeps native SUI expenditure within the accepted i ...[truncated 802 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Implement explicit validation for every relevant `objectChanges` type, including created, mutated, transferred, deleted, wrapped, and published objects. - Establish each input object's pre-transaction owner and compare it with its post-simulation owner. - Collect explicit user intent for expected object IDs, allowed operations, and expected recipients. - Block ownership changes to any address not explicitly authorized by the user. - Block unexpected deletion, wrapping, creation, or mutation of security-sensitive objects. - Treat unknown object-change schemas and unsupported change types as audit failures rather than ignoring them. - Ensure `hijacked_objects` is evaluated before a safe verdict can be emitted. - Add adversarial tests involving NFT transfers, capability diversion, deletion, and object wrapping. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
main.py:47
Finding
Non-SUI Asset Losses Are Excluded from Audit Decisions<![CDATA[ ## Vulnerability Details **File Location**: `main.py:47-59, 84-90` **Vulnerability Type**: Incomplete asset-flow validation **Risk Level**: High ### Vulnerable Code ```python balance_changes = json_data.get("balanceChanges", []) actual_sui_loss = 0.0 # 1. Detect SUI expenditure (PRICE_MISMATCH) for change in balance_changes: if (change.get("owner") == owner_addr or change.get("owner", {}).get("AddressOwner") == owner_addr) \ and change.get("coinType") == "0x2::sui::SUI": amount = int(change.get("amount", 0)) if amount < 0: actual_sui_loss += abs(amount) / 1e9 ``` ```python if actual_sui_loss > (intended_cost + 0.02): print(f"🚨 [RESULT] ❌ MALICIOUS: Price mismatch detected!") print(f" Hidden drain of {actual_sui_loss - intended_cost:.4f} SUI.") sys.exit(1) else: print(f"✅ [RESULT] SAFE TO SIGN.") ``` ### Technical Analysis The `coinType` condition restricts accounting to native SUI. Negative balance changes involving USDC, wrapped assets, LP tokens, protocol tokens, or any other coin type are ignored. The final verdict has no alternative validation path for these assets. A transaction can therefore remove a valuable non-SUI balance while spending only an acceptable amount of SUI for gas. The transaction will pass because the ignored asset loss does not contribute to `actual_sui_loss`. The auditor also does not compare recipients, expected outputs, minimum received amounts, or per-asset direction against user intent. ### Attack Path 1. The user's wallet contains a non-SUI coin, such as a stablecoin or protocol token. 2. An attacker prepares a PTB that transfers that asset to an attacker-controlled address. 3. Native SUI expenditure remains below the declared amount plus the hardcoded gas buffer. 4. The dry-run reports the non-SUI loss in `balanceChanges`. 5. The `coinType == "0x2::sui::SUI"` condition excludes the loss. 6. The native SUI comparison passes and the auditor emits `SAFE TO ...[truncated 403 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Parse and validate every balance change, not only native SUI. - Represent user intent as explicit per-asset constraints containing coin type, maximum spend, minimum receipt, direction, and approved recipient. - Reject any negative balance change that is not explicitly authorized. - Validate expected swap outputs and minimum received amounts. - Normalize coin-type identifiers before comparison and reject malformed or unknown records. - Use exact integer base units for each asset rather than floating-point values. - Add test cases covering stablecoins, LP tokens, arbitrary Move coin types, and transactions containing multiple assets. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
main.py:84
Finding
Non-Finite Intended-Cost Values Bypass the Spending Threshold<![CDATA[ ## Vulnerability Details **File Location**: `main.py:84-90, 96-99` **Vulnerability Type**: Improper numeric input validation **Risk Level**: High ### Vulnerable Code ```python # Criteria: Actual expenditure should not exceed intended cost (plus a 0.02 Gas buffer) if actual_sui_loss > (intended_cost + 0.02): print(f"🚨 [RESULT] ❌ MALICIOUS: Price mismatch detected!") print(f" Hidden drain of {actual_sui_loss - intended_cost:.4f} SUI.") sys.exit(1) else: print(f"✅ [RESULT] SAFE TO SIGN.") ``` ```python raw_cmd = sys.argv[1] intended_cost = float(sys.argv[2]) owner_addr = sys.argv[3] ``` ### Technical Analysis Python's `float()` accepts special values such as `nan`, `inf`, and `Infinity`. The code does not verify that `intended_cost` is finite, non-negative, or within a reasonable range. When `intended_cost` is `nan`, the expression `actual_sui_loss > (nan + 0.02)` evaluates to false for ordinary numeric losses. Positive infinity similarly permits every finite loss. Because the `else` branch prints `SAFE TO SIGN`, these values bypass the only implemented spending threshold. Binary floating-point arithmetic is also inappropriate for authoritative financial limits because it can introduce precision errors, although the non-finite-value bypass is the direct security issue. ### Attack Path 1. An attacker supplies `nan` or `inf` as the intended-cost argument. 2. `float()` accepts the value without raising an exception. 3. The Sui transaction is simulated and may show a substantial native SUI loss. 4. The threshold calculation produces `nan` or positive infinity. 5. The greater-than comparison does not identify the loss as excessive. 6. The auditor executes the safe branch and prints `SAFE TO SIGN`. 7. A relying agent may proceed with the harmful transaction. ### Impact Assessment An attacker who controls or influences the intended-cost argument can completely bypass the native SUI spending limit. The resulting on-chain impact can ...[truncated 125 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Reject non-finite values using `math.isfinite(intended_cost)`. - Enforce a non-negative, application-defined maximum cost. - Prefer parsing SUI amounts with `Decimal` and convert them to exact integer MIST before comparison. - Reject exponent forms, special IEEE-754 values, malformed values, and values with unsupported precision. - Fail closed on every input-validation error. - Add tests for `nan`, `-nan`, `inf`, `-inf`, excessively large values, negative values, and precision-boundary cases. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
main.py:14
Finding
Executable Check Does Not Restrict Commands to Sui PTB Simulations<![CDATA[ ## Vulnerability Details **File Location**: `main.py:14-36` **Vulnerability Type**: Overly broad command authorization **Risk Level**: Medium ### Vulnerable Code ```python # Securely split the string into an argument list using shlex.split args = shlex.split(ptb_command) # Security check: Force the first command to be strictly 'sui' if not args or args[0] != 'sui': print("❌ Security Error: Only 'sui' commands are authorized.") sys.exit(1) # Automatically append required safety detection parameters if '--dry-run' not in args: args.append('--dry-run') if '--json' not in args: args.append('--json') # Core security fix: Execute using a list and disable shell result = subprocess.run( args, capture_output=True, text=True, shell=False # Disable Shell to block RCE attack vectors ) ``` ### Technical Analysis Using `shell=False` and an argument list prevents shell metacharacter injection, but it does not enforce command-level authorization. The validation checks only that the first token is exactly `sui`; it does not require the expected `sui client ptb` subcommand. As a result, the wrapper attempts to execute any `sui` subcommand supplied by the caller under the local user's Sui configuration and wallet context. Appending `--dry-run` and `--json` is not a semantic sandbox and cannot be assumed to make unrelated subcommands safe. Some commands may reject the flags, but relying on downstream CLI behavior is not an adequate least-privilege boundary. The code also does not reject duplicate or conflicting execution, configuration, environment, network, or wallet-selection arguments. ### Attack Path 1. An attacker supplies a command beginning with `sui` but using a subcommand other than the intended `client ptb` operation. 2. The first-token check accepts the command. 3. The wrapper appends `--dry-run` and `--json` without validating whether those flags safely constrain the selected subcommand. 4. `subprocess.run` launche ...[truncated 737 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require the exact command prefix `sui client ptb`. - Parse the command according to an explicit allowlist of supported PTB arguments rather than forwarding arbitrary tokens. - Reject unrelated subcommands and unknown options. - Reject duplicate or conflicting `--dry-run`, execution, network, client-configuration, wallet, and environment options. - Insert controlled safety flags at the correct parser position instead of blindly appending them. - Run the CLI with a minimal environment and an explicitly selected configuration when possible. - Add tests proving that every non-PTB Sui subcommand is rejected before process creation. ]]>
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The skill presents itself as a security gatekeeper that broadly compares transaction behavior against user intent and blocks malicious actions, but the described implementation is materially narrower and incomplete. Overstating detection coverage is dangerous because users may rely on the skill to approve transactions it is not actually capable of validating, creating a false sense of security around potentially malicious smart-contract behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill presents itself as a security gatekeeper that broadly compares transaction behavior against user intent and blocks malicious actions, but the described implementation is materially narrower and incomplete. Overstating detection coverage is dangerous because users may rely on the skill to approve transactions it is not actually capable of validating, creating a false sense of security around potentially malicious smart-contract behavior.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill promises to pre-simulate transactions, compare results against user intent, and block malicious contract behavior, but the implementation only checks aggregate SUI loss against an intended cost threshold. It does not meaningfully verify object transfers, package calls, recipient addresses, token movements, capability transfers, or other side effects, so a malicious transaction could still steal assets or perform unintended actions while being labeled 'SAFE TO SIGN.'

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill invokes shell-capable commands (`python3`, `sui client ...`) but does not declare any explicit tool scope such as `permissions` or `allowed-tools`. That creates an authorization gap where an agent runtime may expose broader shell access than users or platform policy expect, increasing the risk of unintended command execution or abuse if prompt content is manipulated.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
args.append('--json')

        # Core security fix: Execute using a list and disable shell
        result = subprocess.run(
            args,
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Intent-Code Divergence

Medium
Confidence
99% confidence
Finding
The code and comments state that object ownership hijacking is detected, but the relevant loop contains only a placeholder 'pass' and performs no protection. In a security tool whose core purpose is to stop malicious contract behavior, this creates a dangerous false sense of safety: users may trust a 'SAFE TO SIGN' result even when simulated effects transfer NFTs, objects, or capabilities away from the owner.

Static analysis

No suspicious patterns detected.