Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Unsafe Rust

ASecurity

Justify, document, and verify unsafe Rust — safety invariants on every unsafe block, sound safe wrappers, undefined behaviour hazards, and verification with Miri. Use when writing or reviewing unsafe code, when working across an FFI boundary, when raw pointers or transmute appear, when a safe API wraps an unsafe primitive, or when the user asks whether an unsafe block is justified.

2 stars
0 votes
0 copies
0 views
Added 9/19/2026
developmentrustgoc++bashexpressapiperformance

Works with

cliapi

Security Analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned 9/19/2026

$npx -y skills add rewrite-rs/skills --skill unsafe-rust --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Unsafe Rust?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Unsafe Rust
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/rewrite-rs-unsafe-rust/badge)](https://www.skillsdirectory.com/skills/rewrite-rs-unsafe-rust)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: unsafe-rust
description: Justify, document, and verify unsafe Rust — safety invariants on every unsafe block, sound safe wrappers, undefined behaviour hazards, and verification with Miri. Use when writing or reviewing unsafe code, when working across an FFI boundary, when raw pointers or transmute appear, when a safe API wraps an unsafe primitive, or when the user asks whether an unsafe block is justified.
---

# Unsafe Rust

`unsafe` is a promise, not a permission: the code inside may break the rules,
but the code around it must keep them. `unsafe` means undefined behaviour, not
"dangerous" — UB is the compiler being permitted to assume the situation
cannot arise, which is why it surfaces as a later, unrelated miscompile. The
depth is in `SAFETY-REVIEW.md` under `UB is not a bad outcome at runtime`.
This skill governs *soundness* — whether a safe caller can trigger undefined
behaviour — and it never treats "the tests pass" as evidence of soundness.

## `unsafe` does not turn off the borrow checker

It permits exactly five extra operations: dereferencing a raw pointer, calling
an `unsafe fn`, implementing an `unsafe trait`, accessing a `union` field, and
mutating a `static mut`. Everything else — lifetimes, ownership, types — still
applies inside the block. `unsafe` is a narrow escape hatch — reaching for it
to resolve a borrow error is always wrong. That case is `/ownership-not-clone`.

## The justification test

`unsafe` is justified for exactly three reasons. Each has a question that must
be answered before the block is written — and the reason written down, in the
`// SAFETY:` comment or the PR description, not remembered by whoever wrote it.

1. **FFI.** Calling into or out of another language. The checklist: who owns the
   memory on each side, what happens on a panic crossing the boundary (it must
   not), whether the foreign function is thread-safe, and what the lifetime of
   every pointer received actually is. Hand the boundary design to `/rust-ffi`.
   Use the edition 2024 marks on the boundary — those attributes always were
   unsafe assertions; they are in `SAFETY-REVIEW.md` under `Per FFI call`.
2. **A performance win the profile named.** The checklist: what did the
   measurement say, what invariant is being asserted in place of the check,
   and is the safe version genuinely on the hot path — `/rust-performance`
   first, and the answer there is usually that the allocation was the problem.
3. **A primitive the language cannot express safely.** Intrusive structures,
   custom allocators, self-referential types. The checklist: does a crate
   already do this correctly, and is the invariant writable in two sentences.

A block that does not sit under one of these three has an author reaching for
`unsafe` to make an error go away, and the error was right.

## Every `unsafe` block carries a `// SAFETY:` comment

The comment states the invariant the caller upholds, not what the code does:

```rust,ignore
// SAFETY: `ptr` came from `Vec::as_mut_ptr` on a vec of at least `len`
// elements that is still alive for this scope, and no other reference to it
// exists here.
let slice = unsafe { std::slice::from_raw_parts_mut(ptr, len) };
```

And every `pub unsafe fn` carries a `# Safety` doc section stating what the
caller must guarantee. `clippy::undocumented_unsafe_blocks` and
`clippy::missing_safety_doc` are the mechanical check for the two rules:
propose them for the repo lint config, never override a level the repo already
set.

## Soundness is the bar, not "it works"

A safe API is sound when no safe caller can trigger undefined behaviour, for
any input, including malicious ones. Unsound code is never acceptable: there is
no "unsound but only in a case that cannot happen here" — soundness is a
property of the API, and a safe function that can cause UB from safe caller
code is a bug regardless of who currently calls it; fix it or make it
`unsafe fn`. The encapsulation rule: keep the `unsafe` block as small as it can
be, and put the safe/unsafe boundary where the invariant is actually
enforceable — the check belongs in the safe code that guards the block, not in
the block itself. Inside the block, assume the code you call misbehaves — the
depth is in `SAFETY-REVIEW.md`.

## The UB hazards that actually appear

One point each; the review depth is in `SAFETY-REVIEW.md`.

- **Aliasing:** a `&mut` coexisting with any other live reference to the same
  place.
- **Uninitialized memory:** producing a reference to it — use `MaybeUninit<T>`,
  never `mem::zeroed()`: zero is a valid `u32` and an invalid `&T`, `bool`, or
  enum — and the invalidity is instant UB, not a bad value you will notice.
- **Invalid values:** a `bool` that is not 0 or 1, a `char` outside the scalar
  ranges, a null reference.
- **`transmute`:** between types with different layouts, or without
  `#[repr(C)]`/`#[repr(transparent)]` pinning the layout.
- **Unwinding across FFI:** a Rust panic unwinding through a C stack frame.
- **Data races:** shared state mutated without synchronization.

## Reach for the crate that already did it

`bytemuck` for plain-old-data casts, `zerocopy` for zero-copy parsing,
`arrayvec`/`smallvec` for stack-backed collections, an existing binding crate
for an existing C library. Auditing `unsafe` you did not write is cheaper than
justifying it — the audit is the published, reviewed one.

## Deferrals

Whether the wrapper should be `pub`, and what its `unsafe fn` signature commits
the crate to, is `/rust-api-design`. `Pin` and manual `Future` impls interact
with `/async-rust`. Error handling across the boundary is `/rust-errors`.
Construct-level mapping from C or C++ into Rust is `/port-from-c` and
`/port-from-cpp` — this skill covers the `unsafe` discipline, not the mapping.

## Verification

```bash
cargo miri test              # requires the miri component on nightly
cargo clippy --all-targets   # add -- -D warnings only if the repo has no lint config
cargo test
```

If `cargo miri` is unavailable, say so explicitly in the report rather than
silently skipping it, and do not install a nightly toolchain into the user
environment as a side effect. State the Miri limitations plainly so the result
is not over-read: it does not execute FFI calls into real C code, it only
checks the paths the tests actually exercise, and it is slow enough that
targeting the relevant test — `cargo miri test <filter>` — is usually the
practical move. For the FFI side Miri cannot reach, the routes are
`-Zmiri-strict-provenance` for pointer provenance and the address sanitizer for
what a real C library does with the memory.

Attribution

rewrite-rsrewrite-rs
View sourceSee grades on GitHubMore from rewrite-rs →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

285172 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

10311 votes
View all in development →