# Smart Contract Security Review

> Security review for Scalus/Cardano smart contracts. Analyzes @Compile annotated validators for vulnerabilities like redirect attacks, inexact value validation, missing token verification, integer overflow, and self-dealing. Use when reviewing on-chain code, before deploying validators, or when /security-review is invoked. Requires explicit path argument. Use when this capability is needed.

- Skill: `tomevault-io/smart-contract-security-review` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/smart-contract-security-review`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/smart-contract-security-review/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/smart-contract-security-review

---


# Smart Contract Security Review

Analyze Scalus/Cardano smart contracts for security vulnerabilities.

## Target Code Identification

Find on-chain code by searching for:
1. Objects/classes with `@Compile` annotation
2. Objects extending `Validator`, `DataParameterizedValidator`, or `ParameterizedValidator`
3. Objects compiled with `PlutusV3.compile()`, `PlutusV2.compile()`, or `PlutusV1.compile()`

Search patterns:
```
grep -rn "@Compile" --include="*.scala" <path>
grep -rn "extends Validator" --include="*.scala" <path>
grep -rn "extends DataParameterizedValidator" --include="*.scala" <path>
```

## Workflow

1. **Discovery**: Find all `@Compile` annotated code in specified path
2. **Classification**: Identify validator type (spend/mint/reward/certify/vote/propose)
3. **Analysis**: Check each validator against vulnerability checklist
4. **False Positive Verification**: For each potential issue, verify it's not a false positive
5. **Reporting**: Generate structured report with severity levels (only verified issues)
6. **Remediation**: Use TodoWrite to track issues, fix one-by-one with user confirmation

## Vulnerability Checklist

Based on Cardano Developer Portal security guidelines and Scalus-specific patterns.
For detailed patterns and code examples, see `references/vulnerabilities.md`.

### Critical Severity

| ID | Name | Risk | Detection |
|----|------|------|-----------|
| V001 | Redirect Attack | Funds stolen via output redirection | `outputs.at(idx)` without address validation |
| V002 | Token/NFT Not Verified | State token excluded | Missing `quantityOf` on outputs |
| V003 | Inexact Burn/Mint | Extra tokens minted | `>=` instead of `===` for quantities |
| V004 | Integer Overflow | Arithmetic overflow | Custom encoding without bounds |
| V005 | Double Satisfaction | Pay once, satisfy many | `outputs.exists` without unique linking |

### High Severity

| ID | Name | Risk | Detection |
|----|------|------|-----------|
| V006 | Index Validation Missing | Invalid index access | `.at(idx)` without bounds check |
| V007 | Self-Dealing/Shill Bidding | Price manipulation | No seller/bidder separation |
| V008 | Double Spend via Index | Same UTxO processed twice | Index lists without uniqueness |
| V009 | Inexact Refund Amount | Fund manipulation | `>=` for refunds instead of `===` |
| V010 | Other Redeemer Attack | Bypass via different redeemer | Multiple script purposes (always false positive for single-purpose Scalus validators — compiler plugin adds default fail for unimplemented purposes) |
| V011 | Other Token Name Attack | Unauthorized token minting | Policy doesn't check all tokens |
| V012 | Missing UTxO Authentication | Fake UTxO injection | No auth token verification |
| V025 | Oracle Data Validation | Price manipulation, stale data | Oracle data without signature/freshness |

### Medium Severity

| ID | Name | Risk | Detection |
|----|------|------|-----------|
| V013 | Time Handling | Time manipulation | Incorrect interval bounds |
| V014 | Missing Signature | Unauthorized actions | No `isSignedBy` checks |
| V015 | Datum Mutation | Unauthorized state change | No field comparison |
| V016 | Insufficient Staking Control | Reward redirection | No staking credential check |
| V017 | Arbitrary Datum | Unspendable UTxOs | No datum validation |
| V024 | Parameterization Verification | Script substitution (varies) | ParameterizedValidator with auth params, no token |

### Low Severity / Design Issues

| ID | Name | Risk | Detection |
|----|------|------|-----------|
| V018 | Unbounded Value | UTxO size limit | Unlimited tokens in output |
| V019 | Unbounded Datum | Resource exhaustion | Growing datum size |
| V020 | Unbounded Inputs | TX limit exceeded | Many required UTxOs |
| V021 | UTxO Contention / Concurrency DoS | Bottleneck, DoS | Shared global state, no rate limit |
| V022 | Cheap Spam/Dust | Operation obstruction | No minimum amounts |
| V023 | Locked Value | Permanent lock | Missing exit paths |

## False Positive Verification

**CRITICAL**: Before reporting ANY vulnerability, you MUST verify exploitability by tracing code execution with a concrete attack transaction.

### Verification Method: Attack Transaction Tracing

For each potential vulnerability:

1. **Construct a concrete attack transaction**
   - Define specific inputs (UTxOs with concrete values/datums)
   - Define the redeemer values
   - Define the outputs the attacker would create
   - Define signatories

2. **Execute the validator logic mentally with this transaction**
   - Go line-by-line through the validator code
   - Track what each variable evaluates to with your attack tx
   - Check EVERY `require()` statement - does it pass or fail?

3. **If ANY require fails, the attack fails → False Positive**

4. **Only report if ALL requires pass with the attack transaction**

### Example: V005 Double Satisfaction Verification

**Potential vulnerability detected**: `handlePay` uses `getAdaFromOutputs(sellerOutputs)` without unique linking.

**Construct attack transaction**:
```
Inputs:
  - EscrowA: 12 ADA, datum={seller=S, buyer=B, escrowAmount=10, initAmount=2}
  - EscrowB: 12 ADA, datum={seller=S, buyer=B, escrowAmount=10, initAmount=2}
Outputs:
  - 12 ADA to seller S (single output for both!)
  - 1 ADA to buyer B
Signatories: [B]
```

**Trace execution for EscrowA**:
```scala
// Line 57-58:
val contractInputs = txInfo.findOwnInputsByCredential(contractAddress.credential)
// → Returns [EscrowA, EscrowB] (both have same script credential)

val contractBalance = Utils.getAdaFromInputs(contractInputs)
// → 12 + 12 = 24 ADA

// Line 118-120 in handlePay:
require(contractBalance === escrowDatum.escrowAmount + escrowDatum.initializationAmount)
// → require(24 === 10 + 2)
// → require(24 === 12)
// → FAILS! ❌
```

**Result**: Attack transaction fails at line 118-120. This is a **FALSE POSITIVE**.

### When to Write a Test

If the attack trace is complex or you're uncertain, write an actual test:

```scala
test("V005: Double satisfaction attack should fail") {
  // Setup: Create two escrow UTxOs with same seller
  val escrowA = createEscrowUtxo(seller = S, buyer = B, amount = 10.ada)
  val escrowB = createEscrowUtxo(seller = S, buyer = B, amount = 10.ada)

  // Attack: Try to spend both with single output to seller
  val attackTx = Transaction(
    inputs = List(escrowA, escrowB),
    outputs = List(TxOut(sellerAddress, 12.ada)),  // Only pay once!
    redeemers = Map(escrowA -> Pay, escrowB -> Pay)
  )

  // Verify: Should this pass or fail?
  // If it passes → Real vulnerability
  // If it fails → False positive
  evaluateValidator(EscrowValidator, escrowA, attackTx) shouldBe failure
}
```

### Verification Checklist

Before reporting, answer these questions:

| Question | Answer Required |
|----------|-----------------|
| What is the specific attack transaction? | Inputs, outputs, redeemers, signatories |
| Which line would the attacker exploit? | File:line reference |
| Did you trace through EVERY require in the code path? | Yes/No |
| Does the attack pass ALL requires? | Yes (report) / No (false positive) |
| What value does the attacker gain? | Concrete amount/asset |

### Do NOT Report If

- You only found a pattern match without tracing execution
- You haven't constructed a specific attack transaction
- Any `require()` in the code path would fail the attack
- You're unsure whether the attack works (investigate more or write a test)

## Output Format

Use clickable `file_path:line_number` format for all code locations.

### Finding Format

For each vulnerability found, output in this format:

```
### [SEVERITY] ID: Vulnerability Name

**Location:** `full/path/to/File.scala:LINE`
**Method:** methodName

**Issue:** Brief description of what's wrong

**Vulnerable code** (`full/path/to/File.scala:LINE-LINE`):
```scala
// actual code from file
```

**Fix:**
```scala
// proposed fix
```

---
```

### Summary Table

At the end, provide a summary with clickable locations:

```
## Summary

| ID | Severity | Location | Issue | Status |
|----|----------|----------|-------|--------|
| C-01 | Critical | `path/File.scala:123` | Missing mint validation | Fixed |
| H-01 | High | `path/File.scala:87` | Token not in output | Declined |
| M-01 | Medium | `path/File.scala:200` | Missing signature | False Positive |

## False Positives

| ID | Location | Reason |
|----|----------|--------|
| M-01 | `path/File.scala:200` | Authorization is done via NFT ownership in `verifyAuth` helper |

**Security Grade:** A/B/C/D/F
```

### Location Format Rules

1. Always use full path from project root: `scalus-examples/jvm/src/.../File.scala:123`
2. For ranges use: `File.scala:123-145`
3. For method references: `File.scala:123` (methodName)
4. Make locations clickable by using backticks

## Interactive Workflow

For each finding:
1. Display issue with location and proposed fix
2. Prompt: "Apply fix? [y/n/s/d/f]"
   - y: Apply fix, mark completed, verify with `sbtn compile`
   - n: Skip, log as "declined"
   - s: Skip without logging
   - d: Show more details (attack scenario)
   - f: Mark as false positive (prompts for reason, logged to summary)
3. After all findings: run `sbtn quick` to verify fixes
4. Generate summary report including:
   - Fixed issues
   - Declined issues
   - False positives with reasons

## Reference

For detailed vulnerability patterns and code examples, see:
- `references/vulnerabilities.md` - Full pattern documentation with Scalus-specific examples

---
> Source: [scalus3/scalus](https://github.com/scalus3/scalus) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-07-06 -->

