Skip to content
Security
Skill

/inline-assembly

Detect bugs in inline Yul / assembly — manual memory mismanagement, free-memory-pointer corruption, return-data manipulation, missing return-data-size checks, dirty-bits in narrow types. Activate on any `assembly { … }` block, Yul code, Solady-style assembly usage.

From plugin
rugproof
952 skills23 agents45 commands4 hooks
Install
$ npx -y skills add omermaksutii/RugProof --skill inline-assembly --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/inline-assembly

Context preview

The summary Claude sees to decide when to auto-load this skill.

Detect bugs in inline Yul / assembly — manual memory mismanagement, free-memory-pointer corruption, return-data manipulation, missing return-data-size checks, dirty-bits in narrow types. Activate on any `assembly { … }` block, Yul code, Solady-style assembly usage.

SKILL.md

inline-assembly.SKILL.md
name: inline-assembly
description: Detect bugs in inline Yul / assembly — manual memory mismanagement, free-memory-pointer corruption, return-data manipulation, missing return-data-size checks, dirty-bits in narrow types. Activate on any `assembly { … }` block, Yul code, Solady-style assembly usage.

Inline assembly / Yul auditor

When this applies

  • Any `assembly { … }` block
  • Pure Yul contracts
  • Solady's heavy use of optimized assembly
  • Custom delegatecall wrappers, manual memory copy, custom signature verifiers
  • Gas-optimization-driven assembly substitutions of Solidity primitives

Detection patterns

Free-memory-pointer not updated after allocation (HIGH)

assembly {
    let ptr := mload(0x40)
    mstore(ptr, value)
    // ← didn't bump 0x40, next allocation corrupts
}

After writing memory, update `mload(0x40)` to past the write.

Memory clobbering via reused scratch space (HIGH)

Yul scratch is `0x00-0x3F`. External calls / Solidity assignments may overwrite. Don't store across foreign-code boundaries.

Return data not size-checked (HIGH)

assembly {
    let ok := call(gas(), target, 0, in, insz, 0, 32)
    returndatacopy(0, 0, 32)
    let r := mload(0)   // ← if target returned < 32 bytes, r has trailing memory garbage
}

Check `returndatasize()` before copying.

Dirty high bits in narrow types (HIGH)

A `uint8` read from calldata via `calldataload` has the high 248 bits unmasked. Mask with `and(..., 0xff)` before comparing.

Returning attacker-controlled memory (HIGH)

assembly { return(0, calldatasize()) }   // ← returns calldata; if function spec says bytes32, parsers blow up

Mishandling 0x40 / 0x60 (FMP and zero slot) (HIGH)

Writing to `0x60` (zero slot) is a known footgun — that slot must stay zero. Solidity uses it in mappings.

`mstore` to slot 0/0x20 not cleared after a call (MEDIUM-HIGH)

Reused scratch leaks data across functions.

Loop bounds in assembly without checks (HIGH)

Easy to write infinite loops or array-bound-violators.

Wrong opcode (callcode, suicide, gas costs) (HIGH)

Legacy opcodes still parseable but deprecated. `callcode` is the wrong delegatecall; `suicide` is `selfdestruct`.

Address pointers larger than 20 bytes (HIGH)

`address` masked at 20 bytes; assembly users sometimes treat as full 32 bytes and leave dirty bits.

Severity rubric

| Pattern | Severity | |---|---| | Free-memory-pointer corruption | **High** | | Unchecked returndatasize | **High** | | Dirty high bits on narrow type | **High** | | Wrong/legacy opcode | **High** | | Writes to 0x60 (zero slot) | **High** | | Reused scratch across foreign call | **High** | | Assembly returning misformatted ABI data | **High** | | Pure-Yul math with no overflow proof | **High** | | Comment-less assembly block in production code | **Low** *(maintainability)* |

Remediation patterns

  • Prefer audited primitives (OZ, Solady) — don't roll your own assembly.
  • Document every assembly block: invariants, memory map, why.
  • Always update `mload(0x40)` after writes; explicitly zero scratch after use.
  • Check `returndatasize()` before `returndatacopy`.
  • Mask narrow types: `and(x, 0xff)` for `uint8`, `and(x, 0xffff)` for `uint16`, etc.
  • Test with edge-case inputs (zero-length return, oversize return, dirty high bits).

False-positive notes

  • Single-line read of fixed slot (e.g. `chainid()`, `gasprice()`, `caller()`) is safe.
  • Solady's published assembly libraries are audited; using them as-is is fine — verify version pinning.

Related

  • [[assembly-auditor]] (subagent)
  • [[unchecked-calls]]
  • [[storage-layout]]
Read more
Ships withrugproof

Rugproof your code before someone else does. 🌐 Live site: omermaksutii.github.io/RugProof 📦 Latest: v1.0.0 — 45 commands · 23 agents · 45 skills · 13 MCP servers · tested, offline-first, with rule packs, a benchmark, non-EVM coverage, and post-deploy

Get the whole plugin

Other skills on rugproof.