Back to Security & Vulnerability Analysis

sharp-edges

securityAPI designconfigurationfootgunmisuse preventionsecure defaultscryptographysecure by default
5.7k📄 CC-BY-SA-4.0🕒 2026-06-15Source ↗

Install this skill

npx skills add trailofbits/skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

Sharp-edges analysis focuses on identifying interface designs that lead developers toward insecure outcomes. Instead of hunting for syntax bugs, this skill inspects API ergonomics, configuration structures, and type systems to find where the path of least resistance is fundamentally broken. It targets scenarios where reasonable-looking code allows for dangerous algorithm selection, insecure defaults, or type confusion. By evaluating how an API forces or encourages secure behavior, this analysis shifts security left, preventing vulnerabilities before they are coded. It centers on the philosophy that secure choices should be the default, and developers should not need to be cryptographic experts to avoid common pitfalls. This ensures the architecture itself prevents misuse rather than relying on perfect documentation or constant vigilance from the implementer.

When to Use This Skill

  • Reviewing new internal library APIs to ensure secure usage by default
  • Auditing configuration object builders for missing or insecure defaults
  • Validating that cryptographic wrappers prevent common nonce or key reuse
  • Refactoring APIs that accept raw strings where specific types should be enforced

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • Is this API easy to misuse?
  • Check for cryptographic footguns in this module
  • Identify insecure defaults in this configuration schema
  • Does this function allow dangerous algorithm selection?
  • Review this API for common security design flaws

Pro Tips

  • 💡Apply this skill early in the design phase, before significant code is written, to catch fundamental architectural security flaws and save refactoring effort.
  • 💡When prompted, ask the AI to suggest alternative, more misuse-resistant API designs or configuration options for identified 'sharp edges'.
  • 💡Combine with general code review skills to ensure both design and implementation adhere to secure principles and best practices.

What this skill does

  • Detects cryptographic algorithm choices that invite downgrade attacks
  • Identifies dangerous default values that silently weaken security
  • Evaluates type safety to prevent swapping security-sensitive parameters
  • Audits configuration schemas for magic values that disable protections
  • Analyzes API surface area for excessive flexibility that creates footguns

When not to use it

  • Finding specific implementation bugs like buffer overflows
  • Assessing business logic flaws specific to your application domain
  • Performance tuning or latency benchmarking

Example workflow

  1. Map out the primary security-critical parameters in the target API
  2. Test boundary conditions such as null, empty, or zero values
  3. Verify whether the API forces strong defaults or allows insecure overrides
  4. Attempt to pass invalid types to check for runtime enforcement
  5. Document findings and propose a more restrictive API wrapper

Prerequisites

  • API documentation or source code
  • Understanding of the security requirements for the specific protocol

Pitfalls & limitations

  • !Focusing on syntax rather than the ergonomics of the API design
  • !Assuming advanced users need full, unconstrained flexibility
  • !Ignoring how configuration loaders handle invalid inputs

FAQ

How is this different from a standard code review?
Standard code reviews look for bugs in implementation. This analysis focuses on the design of the interface, specifically whether the API itself makes it too easy to write insecure code.
What is a 'footgun' in this context?
A footgun is a feature or design choice that makes it easy for a developer to accidentally introduce a vulnerability, such as a function that accepts an unsafe cryptographic mode by default.
Can I use this on existing legacy code?
Yes. It is particularly useful for identifying where to wrap legacy functions in safer, more opinionated interfaces to prevent future misuse.

How it compares

While manual reviews rely on subjective experience, this systematic approach uses specific detection patterns for common anti-patterns like algorithm confusion and type swapping.

Source & trust

5.7k stars📄 CC-BY-SA-4.0🕒 Updated 2026-06-15
📄 Full skill instructions — original source: trailofbits/skills
# Sharp Edges Analysis

Evaluates whether APIs, configurations, and interfaces are resistant to developer misuse. Identifies designs where the "easy path" leads to insecurity.

## When to Use

- Reviewing API or library design decisions
- Auditing configuration schemas for dangerous options
- Evaluating cryptographic API ergonomics
- Assessing authentication/authorization interfaces
- Reviewing any code that exposes security-relevant choices to developers

## When NOT to Use

- Implementation bugs (use standard code review)
- Business logic flaws (use domain-specific analysis)
- Performance optimization (different concern)

## Core Principle

**The pit of success**: Secure usage should be the path of least resistance. If developers must understand cryptography, read documentation carefully, or remember special rules to avoid vulnerabilities, the API has failed.

## Rationalizations to Reject

| Rationalization | Why It's Wrong | Required Action |
|-----------------|----------------|-----------------|
| "It's documented" | Developers don't read docs under deadline pressure | Make the secure choice the default or only option |
| "Advanced users need flexibility" | Flexibility creates footguns; most "advanced" usage is copy-paste | Provide safe high-level APIs; hide primitives |
| "It's the developer's responsibility" | Blame-shifting; you designed the footgun | Remove the footgun or make it impossible to misuse |
| "Nobody would actually do that" | Developers do everything imaginable under pressure | Assume maximum developer confusion |
| "It's just a configuration option" | Config is code; wrong configs ship to production | Validate configs; reject dangerous combinations |
| "We need backwards compatibility" | Insecure defaults can't be grandfather-claused | Deprecate loudly; force migration |

## Sharp Edge Categories

### 1. Algorithm/Mode Selection Footguns

APIs that let developers choose algorithms invite choosing wrong ones.

**The JWT Pattern** (canonical example):
- Header specifies algorithm: attacker can set "alg": "none" to bypass signatures
- Algorithm confusion: RSA public key used as HMAC secret when switching RS256→HS256
- Root cause: Letting untrusted input control security-critical decisions

**Detection patterns:**
- Function parameters like algorithm, mode, cipher, hash_type
- Enums/strings selecting cryptographic primitives
- Configuration options for security mechanisms

**Example - PHP password_hash allowing weak algorithms:**
// DANGEROUS: allows crc32, md5, sha1
password_hash($password, PASSWORD_DEFAULT); // Good - no choice
hash($algorithm, $password); // BAD: accepts "crc32"


### 2. Dangerous Defaults

Defaults that are insecure, or zero/empty values that disable security.

**The OTP Lifetime Pattern:**
# What happens when lifetime=0?
def verify_otp(code, lifetime=300): # 300 seconds default
if lifetime == 0:
return True # OOPS: 0 means "accept all"?
# Or does it mean "expired immediately"?


**Detection patterns:**
- Timeouts/lifetimes that accept 0 (infinite? immediate expiry?)
- Empty strings that bypass checks
- Null values that skip validation
- Boolean defaults that disable security features
- Negative values with undefined semantics

**Questions to ask:**
- What happens with timeout=0? max_attempts=0? key=""?
- Is the default the most secure option?
- Can any default value disable security entirely?

### 3. Primitive vs. Semantic APIs

APIs that expose raw bytes instead of meaningful types invite type confusion.

**The Libsodium vs. Halite Pattern:**

// Libsodium (primitives): bytes are bytes
sodium_crypto_box($message, $nonce, $keypair);
// Easy to: swap nonce/keypair, reuse nonces, use wrong key type

// Halite (semantic): types enforce correct usage
Crypto::seal($message, new EncryptionPublicKey($key));
// Wrong key type = type error, not silent failure


**Detection patterns:**
- Functions taking bytes, string, []byte for distinct security concepts
- Parameters that could be swapped without type errors
- Same type used for keys, nonces, ciphertexts, signatures

**The comparison footgun:**
// Timing-safe comparison looks identical to unsafe
if hmac == expected { } // BAD: timing attack
if hmac.Equal(mac, expected) { } // Good: constant-time
// Same types, different security properties


### 4. Configuration Cliffs

One wrong setting creates catastrophic failure, with no warning.

**Detection patterns:**
- Boolean flags that disable security entirely
- String configs that aren't validated
- Combinations of settings that interact dangerously
- Environment variables that override security settings
- Constructor parameters with sensible defaults but no validation (callers can override with insecure values)

**Examples:**
# One typo = disaster
verify_ssl: fasle # Typo silently accepted as truthy?

# Magic values
session_timeout: -1 # Does this mean "never expire"?

# Dangerous combinations accepted silently
auth_required: true
bypass_auth_for_health_checks: true
health_check_path: "/" # Oops


// Sensible default doesn't protect against bad callers
public function __construct(
public string $hashAlgo = 'sha256', // Good default...
public int $otpLifetime = 120, // ...but accepts md5, 0, etc.
) {}


See [config-patterns.md](references/config-patterns.md#unvalidated-constructor-parameters) for detailed patterns.

### 5. Silent Failures

Errors that don't surface, or success that masks failure.

**Detection patterns:**
- Functions returning booleans instead of throwing on security failures
- Empty catch blocks around security operations
- Default values substituted on parse errors
- Verification functions that "succeed" on malformed input

**Examples:**
# Silent bypass
def verify_signature(sig, data, key):
if not key:
return True # No key = skip verification?!

# Return value ignored
signature.verify(data, sig) # Throws on failure
crypto.verify(data, sig) # Returns False on failure
# Developer forgets to check return value


### 6. Stringly-Typed Security

Security-critical values as plain strings enable injection and confusion.

**Detection patterns:**
- SQL/commands built from string concatenation
- Permissions as comma-separated strings
- Roles/scopes as arbitrary strings instead of enums
- URLs constructed by joining strings

**The permission accumulation footgun:**
permissions = "read,write"
permissions += ",admin" # Too easy to escalate

# vs. type-safe
permissions = {Permission.READ, Permission.WRITE}
permissions.add(Permission.ADMIN) # At least it's explicit


## Analysis Workflow

### Phase 1: Surface Identification

1. **Map security-relevant APIs**: authentication, authorization, cryptography, session management, input validation
2. **Identify developer choice points**: Where can developers select algorithms, configure timeouts, choose modes?
3. **Find configuration schemas**: Environment variables, config files, constructor parameters

### Phase 2: Edge Case Probing

For each choice point, ask:
- **Zero/empty/null**: What happens with 0, "", null, []?
- **Negative values**: What does -1 mean? Infinite? Error?
- **Type confusion**: Can different security concepts be swapped?
- **Default values**: Is the default secure? Is it documented?
- **Error paths**: What happens on invalid input? Silent acceptance?

### Phase 3: Threat Modeling

Consider three adversaries:

1. **The Scoundrel**: Actively malicious developer or attacker controlling config
- Can they disable security via configuration?
- Can they downgrade algorithms?
- Can they inject malicious values?

2. **The Lazy Developer**: Copy-pastes examples, skips documentation
- Will the first example they find be secure?
- Is the path of least resistance secure?
- Do error messages guide toward secure usage?

3. **The Confused Developer**: Misunderstands the API
- Can they swap parameters without type errors?
- Can they use the wrong key/algorithm/mode by accident?
- Are failure modes obvious or silent?

### Phase 4: Validate Findings

For each identified sharp edge:

1. **Reproduce the misuse**: Write minimal code demonstrating the footgun
2. **Verify exploitability**: Does the misuse create a real vulnerability?
3. **Check documentation**: Is the danger documented? (Documentation doesn't excuse bad design, but affects severity)
4. **Test mitigations**: Can the API be used safely with reasonable effort?

If a finding seems questionable, return to Phase 2 and probe more edge cases.

## Severity Classification

| Severity | Criteria | Examples |
|----------|----------|----------|
| Critical | Default or obvious usage is insecure | verify: false default; empty password allowed |
| High | Easy misconfiguration breaks security | Algorithm parameter accepts "none" |
| Medium | Unusual but possible misconfiguration | Negative timeout has unexpected meaning |
| Low | Requires deliberate misuse | Obscure parameter combination |

## References

**By category:**

- **Cryptographic APIs**: See [references/crypto-apis.md](references/crypto-apis.md)
- **Configuration Patterns**: See [references/config-patterns.md](references/config-patterns.md)
- **Authentication/Session**: See [references/auth-patterns.md](references/auth-patterns.md)
- **Real-World Case Studies**: See [references/case-studies.md](references/case-studies.md) (OpenSSL, GMP, etc.)

**By language** (general footguns, not crypto-specific):

| Language | Guide |
|----------|-------|
| C/C++ | [references/lang-c.md](references/lang-c.md) |
| Go | [references/lang-go.md](references/lang-go.md) |
| Rust | [references/lang-rust.md](references/lang-rust.md) |
| Swift | [references/lang-swift.md](references/lang-swift.md) |
| Java | [references/lang-java.md](references/lang-java.md) |
| Kotlin | [references/lang-kotlin.md](references/lang-kotlin.md) |
| C# | [references/lang-csharp.md](references/lang-csharp.md) |
| PHP | [references/lang-php.md](references/lang-php.md) |
| JavaScript/TypeScript | [references/lang-javascript.md](references/lang-javascript.md) |
| Python | [references/lang-python.md](references/lang-python.md) |
| Ruby | [references/lang-ruby.md](references/lang-ruby.md) |

See also [references/language-specific.md](references/language-specific.md) for a combined quick reference.

## Quality Checklist

Before concluding analysis:

- [ ] Probed all zero/empty/null edge cases
- [ ] Verified defaults are secure
- [ ] Checked for algorithm/mode selection footguns
- [ ] Tested type confusion between security concepts
- [ ] Considered all three adversary types
- [ ] Verified error paths don't bypass security
- [ ] Checked configuration validation
- [ ] Constructor params validated (not just defaulted) - see [config-patterns.md](references/config-patterns.md#unvalidated-constructor-parameters)

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/sharp-edges/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/trailofbits/skills/sharp-edges/SKILL.md
  • Cursor: ~/.cursor/skills/trailofbits/skills/sharp-edges/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/trailofbits/skills/sharp-edges/SKILL.md

🚀 Install with CLI:
npx skills add trailofbits/skills

Read the Master Guide: Mastering Agent Skills

Recommended Rules

View more rules

Recommended Workflows

View more workflows

Recommended MCP Servers

View more MCP servers

Take It Further

Maximize your productivity with these powerful resources

📋

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
📖

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid security & vulnerability analysis issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under Security & Vulnerability Analysis and is published by Trail of Bits, maintained in trailofbits/skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.