Back to skill

Security audit

Write Contracts

Security checks for vulnerabilities and agentic risk

Overview

This is a documentation-only Aptos contract-writing skill, but its broad activation scope and a few unsafe examples could lead to incorrect or vulnerable smart-contract output.

Review this skill before installation if you expect it to generate production smart contracts. Narrow its activation to explicit Aptos/Move requests and fix or ignore the unsafe examples before relying on generated code; independently audit and test any contract before deployment.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
references/storage-patterns.md:142
Finding

Unauthenticated Public Function Permits Forged Audit-Log Records

Content
View full analysis

Vulnerability Details

File Location: references/storage-patterns.md, lines 142-155
Vulnerability Type: Missing authentication and caller impersonation
Risk Level: Medium

move
public entry fun log_transaction(
    action: String,
    executor: address,
    amount: u64
) acquires AuditLog {
    let log = borrow_global_mut<AuditLog>(@my_addr);
    smart_vector::push_back(&mut log.transactions, TxRecord {
        timestamp: timestamp::now_seconds(),
        action,
        executor,
        amount,
    });
}

Technical Analysis

The reusable example exposes log_transaction as a public entry function without accepting a signer or performing an authorization check. Consequently, any transaction sender can invoke it.

The executor field is supplied directly by the caller rather than being derived from an authenticated signer. An attacker can therefore attribute an arbitrary action and amount to any address, including an administrator or another user. The record is then appended to the authoritative on-chain AuditLog.

The function also lacks validation or size limits for action and does not constrain amount. Repeated calls can grow the stored log and impose avoidable storage costs.

Attack Path

  1. The victim deploys a contract based on this documented storage pattern.
  2. An attacker invokes the public log_transaction entry function.
  3. The attacker supplies a privileged or victim address as executor.
  4. The attacker supplies arbitrary action and amount values.
  5. The function appends the forged record without checking the transaction sender.
  6. Indexers, monitoring systems, accounting logic, or users may treat the forged record as an authentic action by the impersonated address.
  7. The attacker can repeat the operation to pollute the log and increase storage consumption.

Impact Assessment

This issue does not directly grant account or admin ...[truncated 544 chars]

Remediation
View remediation

Remediation Suggestions

  • Add a caller: &signer parameter to the entry function.
  • Derive the executor from signer::address_of(caller) instead of accepting an arbitrary executor address.
  • If only trusted code may create records, compare the caller against a stored administrator or operator role before modifying the log.
  • Validate action with non-empty and maximum-length constraints.
  • Validate amount according to the application’s permitted range.
  • Emit authenticated events instead of maintaining an indefinitely growing on-chain history when records are only needed for off-chain querying.
  • If on-chain storage is required, implement retention or bounded-capacity controls.

A safer interface would follow this structure:

move
public entry fun log_transaction(
    caller: &signer,
    action: String,
    amount: u64
) acquires AuditLog {
    let executor = signer::address_of(caller);
    // Validate caller authority, action length, and amount here.
    // Append the authenticated record or emit an event.
}

T09 · Insecure Skill Coding Practices

Note
Location
references/safe-arithmetic.md:78
Finding

Percentage Helper Can Abort Due to Unchecked Multiplication Overflow

Content
View full analysis

Vulnerability Details

File Location: references/safe-arithmetic.md, lines 78-89
Vulnerability Type: Integer overflow and transaction denial of service
Risk Level: Low

move
// Error constants
const E_INVALID_PERCENTAGE: u64 = 14;
const BASIS_POINTS_DIVISOR: u64 = 10000; // 100% = 10000 basis points

/// Calculate percentage of amount
/// percentage: 250 = 2.5%, 1000 = 10%, 10000 = 100%
public fun percentage_of(amount: u64, percentage_bp: u64): u64 {
    assert!(percentage_bp <= BASIS_POINTS_DIVISOR, E_INVALID_PERCENTAGE);

    // Multiply first for precision, then divide
    (amount * percentage_bp) / BASIS_POINTS_DIVISOR
}

Technical Analysis

The helper constrains percentage_bp to 10,000 or less but does not verify that amount * percentage_bp fits within a u64. For any nonzero percentage, sufficiently large valid amount values cause the intermediate multiplication to overflow before division occurs.

Aptos Move arithmetic aborts on overflow rather than wrapping silently. This protects value integrity, but an attacker-controlled or naturally large input can still force the surrounding transaction to abort. The example is particularly concerning because it appears in documentation specifically presented as a safe arithmetic pattern and may be copied into fee, reward, settlement, or withdrawal logic.

Attack Path

  1. A generated contract adopts the documented percentage_of helper.
  2. A public operation passes a user-controlled or sufficiently large amount to the helper.
  3. The attacker chooses a valid nonzero percentage_bp, or the contract supplies one from its configuration.
  4. The product exceeds the maximum u64 value even though both individual inputs are valid.
  5. Move aborts during amount * percentage_bp.
  6. The enclosing operation, such as settlement, fee collection, reward calculation, or withdrawal, fails.

Impact Assessment

The issue does not p ...[truncated 444 chars]

Remediation
View remediation

Remediation Suggestions

  • Validate the multiplication before performing it.
  • Handle a zero percentage separately to avoid division in the overflow guard.
  • Assert that amount <= MAX_U64 / percentage_bp whenever percentage_bp is nonzero.
  • Use a wider intermediate integer type if the target Aptos Move environment and application design support it.
  • Add boundary tests covering zero, MAX_U64, 10,000 basis points, and the largest non-overflowing amount.

Example hardened logic:

move
public fun percentage_of(amount: u64, percentage_bp: u64): u64 {
    assert!(percentage_bp <= BASIS_POINTS_DIVISOR, E_INVALID_PERCENTAGE);

    if (percentage_bp == 0) {
        0
    } else {
        assert!(amount <= MAX_U64 / percentage_bp, E_OVERFLOW);
        (amount * percentage_bp) / BASIS_POINTS_DIVISOR
    }
}
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The trigger phrases are very broad for a high-priority skill and overlap with common developer requests such as 'write contract' or 'build marketplace'. This can cause unintended activation, leading the agent to inject contract-generation behavior into unrelated conversations and increasing the chance of unsafe or irrelevant code suggestions in a security-sensitive domain.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 259)May include surrounding context.

md
4. ❌ **Never skip signer verification** in entry functions
5. ❌ **Never skip input validation** (amounts, addresses, strings)
6. ❌ **Never deploy without 100% test coverage**
7. ❌ **Never create helper functions** that just return named addresses
8. ❌ **Never skip event emission** for significant activities
9. ❌ **Never use old syntax** when V2 syntax is available
10. ❌ **Never skip init_module** for contracts that need initialization

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The prose says the function 'allows anyone to update' and warns to add authorization in production, but the actual code immediately enforces an ownership check with assert!(object::owner(obj) == signer::address_of(owner), E_NOT_OWNER). In a contract-generation skill, this contradiction is dangerous because developers may copy the surrounding explanation instead of the code, weaken the check during adaptation, or misunderstand ExtendRef as inherently bypassing authorization.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This is a true issue: the documentation presents the percentage helper as a safe arithmetic pattern, but (amount * percentage_bp) / BASIS_POINTS_DIVISOR can overflow on the multiplication before division occurs. In a contract-generation skill focused on secure Move code, this is especially dangerous because users may copy the example directly and assume it is vetted, causing transaction aborts or broken business logic in financial calculations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code example performs unchecked multiplication in a section about safe arithmetic, which can overflow for large inputs even though the percentage is bounded to 10000 basis points. Because this skill generates smart contract guidance, the unsafe example may be propagated into production Move modules, leading to aborts and denial-of-service conditions for edge-case values.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger list includes very generic terms like "store", "track", "registry", "mapping", "collection", and "list", which can cause the skill to activate in unrelated contexts. In an agentic environment, unintended invocation can lead to incorrect contract-generation guidance being injected into conversations or workflows where it was not requested, increasing confusion and the chance of unsafe or irrelevant code suggestions.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.