{"id":30176056,"url":"https://github.com/yevh/rust-security-handbook","last_synced_at":"2025-08-12T02:19:24.780Z","repository":{"id":301181297,"uuid":"1008429324","full_name":"yevh/rust-security-handbook","owner":"yevh","description":"A 10-chapter handbook for writing actually secure Rust: type-safety, panic-proofing \u0026 more.","archived":false,"fork":false,"pushed_at":"2025-06-25T14:30:40.000Z","size":11,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-25T15:31:55.061Z","etag":null,"topics":["rust","security"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yevh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-25T14:28:10.000Z","updated_at":"2025-06-25T14:40:24.000Z","dependencies_parsed_at":"2025-06-25T15:44:21.360Z","dependency_job_id":null,"html_url":"https://github.com/yevh/rust-security-handbook","commit_stats":null,"previous_names":["yevh/rust-security-handbook"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/yevh/rust-security-handbook","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yevh%2Frust-security-handbook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yevh%2Frust-security-handbook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yevh%2Frust-security-handbook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yevh%2Frust-security-handbook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yevh","download_url":"https://codeload.github.com/yevh/rust-security-handbook/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yevh%2Frust-security-handbook/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269987332,"owners_count":24508223,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rust","security"],"created_at":"2025-08-12T02:19:22.208Z","updated_at":"2025-08-12T02:19:24.761Z","avatar_url":"https://github.com/yevh.png","language":null,"funding_links":[],"categories":["Resources"],"sub_categories":["Web programming"],"readme":"# The Complete Rust Security Handbook: From Safe Code to Unbreakable Systems\n\n*\"Rust prevents you from shooting yourself in the foot with memory corruption, but it can't stop you from aiming the gun at your users' money.\" - The Security Rustacean's Creed*\n\n## Prologue: The Three Pillars of Rust Security\n\nRust gives you memory safety for free, but **application security** is earned through discipline. This guide will teach you to think like both a Rustacean and a security engineer, because in production systems, being \"mostly secure\" is like being \"mostly pregnant.\"\n\n**The Security Trinity:**\n1. **Type Safety** - Make invalid states impossible to represent\n2. **Error Safety** - Turn panics into controlled failures  \n3. **Secret Safety** - What happens in RAM should stay in RAM (until properly zeroized)\n\n---\n\n## Chapter 1: The Type System - Your First Line of Defense\n\n### Why Primitives Are Security Vulnerabilities\n\nEvery `u64` in your API is a potential million-dollar bug waiting to happen:\n\n```rust\n// ⚠️ Three bare u64s – compiler can’t tell them apart\nfn transfer(from: u64, to: u64, amount: u64) -\u003e Result\u003c(), Error\u003e {\n    // What happens when a tired developer swaps these at 2 AM?\n    // transfer(balance, user_id, amount) ← 💥 Goodbye money\n}\n```\n\nIn traditional languages, this compiles and runs. In blockchain contexts, it transfers user ID `12345` tokens from account `67890`. The code works perfectly—it just transfers money to the wrong place.\n\n### The Newtype Pattern: Zero-Cost Type Safety\n\nWrap every meaningful primitive in a semantic type:\n\n```rust\n// ✅ Type-safe: cross-type swaps won’t compile\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\nstruct UserId(u64);\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\nstruct Balance(u64);\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\nstruct TokenAmount(u64);\n\n// Cross-type swaps now fail to compile\nfn transfer(from: UserId, to: UserId, amount: TokenAmount) -\u003e Result\u003c(), Error\u003e {\n    // Swapping two UserId values still compiles — keep names clear\n}\n```\n\n**The Magic:** These wrappers vanish at compile time (zero runtime cost) while preventing cross-type parameter swaps.\n\n### Real-World Impact: The Merkle Root Mixup\n\n```rust\n// ❌ PRODUCTION INCIDENT: All roots look the same\nfn verify_proof(root: [u8; 32], proof: Vec\u003c[u8; 32]\u003e, leaf: [u8; 32]) -\u003e bool {\n    // merkle verification logic\n}\n\n// Oops - passed balance root where nullifier root expected\nlet valid = verify_proof(balance_root, proof, nullifier_hash); // 💥 Logic bug\n```\n\n```rust\n// ✅ BULLETPROOF: Each root type is distinct\nstruct BalanceRoot([u8; 32]);\nstruct NullifierRoot([u8; 32]);\n\nfn verify_balance_proof(root: BalanceRoot, proof: Vec\u003c[u8; 32]\u003e, leaf: [u8; 32]) -\u003e bool {\n    // verification logic\n}\n\n// This won't compile - the type system saves us!\nlet valid = verify_balance_proof(nullifier_root, proof, leaf); // ❌ Compile error\n```\n\n**When to Use Newtypes (Answer: Almost Always):**\n- IDs, hashes, roots, keys, addresses, nonces\n- Business values (Price, Balance, Quantity)\n- Validated data (Email, PhoneNumber)  \n- Array indices with specific meaning\n\n---\n\n## Chapter 2: Error Handling - When unwrap() Becomes a Weapon\n\n### The unwrap() Time Bomb\n\nIn Web3 and financial systems, panics aren't just crashes—they're **denial-of-service attacks**:\n\n```rust\n// ❌ DOS VULNERABILITY\nfn calculate_fee(amount: u64, rate: u64) -\u003e u64 {\n    amount.checked_mul(rate).unwrap() / 10000  // 💥 Panic = burned gas + no tx\n}\n```\n\nAn attacker provides values that cause overflow, the transaction panics, the user's gas is burned, and nothing happens. Repeat this attack to effectively DoS a smart contract.\n\n### The ? Operator: Graceful Degradation\n\n```rust\n// ✅ GRACEFUL FAILURE\nfn calculate_fee_safe(amount: u64, rate: u64) -\u003e Result\u003cu64, FeeError\u003e {\n    let fee_total = amount\n        .checked_mul(rate)\n        .ok_or(FeeError::Overflow)?;  // Returns error instead of panic\n    \n    Ok(fee_total / 10000)\n}\n```\n\n**The ? Operator Magic:**\n- `Ok(value)` → extracts value and continues\n- `Err(error)` → returns early with error\n- No panics, no DoS vectors, just controlled failure\n\n### When unwrap() is Actually Safe\n\nSometimes unwrap() is mathematically provable to be safe:\n\n```rust\n// ✅ SAFE: Vector was just created with known size\nlet numbers = vec![1, 2, 3, 4, 5];\nlet first = numbers.get(0).expect(\"vector has 5 elements\");\n\n// ✅ SAFE: We just checked the condition\nif !user_input.is_empty() {\n    let first_char = user_input.chars().next().unwrap();\n}\n```\n\n**Rule:** If you can't write a comment explaining why the `unwrap()` can't fail, it probably can.\n\n---\n\n## Chapter 3: Integer Arithmetic - Where Money Goes to Die\n\n### The Silent Killer: Integer Overflow\n\nRust silently wraps overflows in release mode by default, turning your financial calculations into random number generators:\n\n```rust\n// ❌ SILENT MONEY CORRUPTION\nfn add_to_balance(current: u64, deposit: u64) -\u003e u64 {\n    current + deposit  // If this overflows: u64::MAX + 1 = 0\n}\n\n// User has maximum balance, deposits 1 wei → balance becomes 0!\n```\n\nThis isn't theoretical. Integer overflow has caused real financial losses in production systems.\n\n### The Three Pillars of Safe Arithmetic\n\n#### 1. Checked Arithmetic - For Critical Money Operations\n\n```rust\n// ✅ OVERFLOW DETECTION\nfn add_to_balance_safe(current: u64, deposit: u64) -\u003e Result\u003cu64, BalanceError\u003e {\n    current\n        .checked_add(deposit)\n        .ok_or(BalanceError::Overflow)\n}\n```\n\n**Use for:** Money, prices, balances, critical calculations\n\n#### 2. Saturating Arithmetic - For Counters and Limits\n\n```rust\n// ✅ CLAMPING TO BOUNDS\nfn apply_penalty(reputation: u32, penalty: u32) -\u003e u32 {\n    reputation.saturating_sub(penalty)  // Never goes below 0\n}\n\nfn increment_counter(count: u32) -\u003e u32 {\n    count.saturating_add(1)  // Never overflows, just stays at MAX\n}\n```\n\n**Use for:** Counters, reputation systems, rate limiting\n\n#### 3. Wrapping Arithmetic - For Hash Functions\n\n```rust\n// ✅ EXPLICIT WRAPAROUND\nfn hash_combine(hash: u32, value: u32) -\u003e u32 {\n    hash.wrapping_mul(31).wrapping_add(value)  // Wraparound is expected\n}\n```\n\n**Use for:** Cryptographic operations where wraparound is mathematically correct\n\n### Financial Calculation Best Practices\n\n```rust\n// ❌ WRONG: Float precision and rounding issues\nfn calculate_fee_wrong(amount: u64, rate_percent: f64) -\u003e u64 {\n    (amount as f64 * rate_percent / 100.0).round() as u64  // 💥 Precision loss\n}\n\n// ✅ CORRECT: Integer arithmetic with explicit rounding\nfn calculate_fee_correct(amount: u64, rate_bps: u64) -\u003e Result\u003cu64, Error\u003e {\n    // Multiply first, then divide (order matters!)\n    let fee_precise = amount\n        .checked_mul(rate_bps)\n        .ok_or(Error::Overflow)?;\n    \n    // For fees: round UP (ceiling division)\n    let fee = fee_precise / 10000;\n    if fee_precise % 10000 \u003e 0 {\n        fee.checked_add(1).ok_or(Error::Overflow)\n    } else {\n        Ok(fee)\n    }\n}\n\nfn calculate_payout(amount: u64, rate_bps: u64) -\u003e Result\u003cu64, Error\u003e {\n    // For payouts: round DOWN (floor division)\n    amount\n        .checked_mul(rate_bps)\n        .and_then(|x| x.checked_div(10000))\n        .ok_or(Error::Overflow)\n}\n```\n\n**Golden Rules:**\n- **Fees/charges:** Round UP (never under-collect)\n- **Payouts/refunds:** Round DOWN (never overpay)\n- **Always multiply first, then divide**\n- **Use basis points (bps) instead of floats for rates**\n\n### Enable Runtime Overflow Checks\n\n```toml\n[profile.release]\noverflow-checks = true  # Panic instead of silent wraparound\n```\n\n---\n\n## Chapter 4: Cryptography and Secrets - The Art of Digital Locks\n\n### Random Numbers: The Foundation of Security\n\nCryptographic security often reduces to: \"Can an attacker predict this number?\"\n\n```rust\n// ❌ PREDICTABLE = BROKEN\nuse rand::{Rng, rngs::StdRng, SeedableRng};\nlet mut rng = StdRng::seed_from_u64(42);  // Same seed = same sequence!\nlet private_key: [u8; 32] = rng.gen();    // Predictable = stolen funds\n```\n\n```rust\n// ✅ CRYPTOGRAPHICALLY SECURE\nuse rand::rngs::OsRng;\nlet private_key: [u8; 32] = OsRng.gen();  // Pulls from OS entropy pool\n```\n\n**Rule:** If it protects secrets or money, use `OsRng`. If it's for gameplay or testing, deterministic is fine.\n\n### Secret Lifecycle Management\n\nSecrets don't just disappear when you think they do:\n\n```rust\n// ❌ SECRET LIVES FOREVER IN MEMORY\nlet mut password = String::from(\"super_secret_password\");\npassword.clear();  // Only changes length - data remains in RAM!\n```\n\n```rust\n// ✅ CRYPTOGRAPHICALLY SECURE WIPING\nuse zeroize::{Zeroize, Zeroizing};\n\n// Manual zeroization\nlet mut secret = [0u8; 32];\nOsRng.fill_bytes(\u0026mut secret);\n// ... use secret ...\nsecret.zeroize();  // Overwrites memory with zeros\n\n// Automatic zeroization \nlet api_key = Zeroizing::new(load_api_key());\n// Automatically zeroized when dropped\n```\n\n### The Debug Trait Trap\n\n```rust\n// ❌ SECRETS IN LOGS\n#[derive(Debug)]\nstruct ApiCredentials {\n    key: String,\n    secret: String,\n}\n\nlet creds = ApiCredentials { /* ... */ };\nprintln!(\"Credentials: {:?}\", creds);  // Logged forever!\n```\n\n```rust\n// ✅ REDACTED LOGGING\nuse secrecy::{Secret, ExposeSecret};\n\nstruct ApiCredentials {\n    key: String,\n    secret: Secret\u003cString\u003e,\n}\n\nlet creds = ApiCredentials {\n    key: \"public_key\".to_string(),\n    secret: Secret::new(\"very_secret\".to_string()),\n};\n\nprintln!(\"Credentials: key={}, secret=[REDACTED]\", creds.key);\n\n// Only expose when absolutely necessary\nlet actual_secret = creds.secret.expose_secret();\n```\n\n### Safe Cryptographic Patterns\n\n```rust\n// ✅ AUTHENTICATED ENCRYPTION (never use raw encryption!)\nuse aes_gcm::{Aes256Gcm, Key, Nonce, aead::{Aead, NewAead}};\n\nfn encrypt_secure(plaintext: \u0026[u8], key: \u0026[u8; 32]) -\u003e Result\u003cVec\u003cu8\u003e, Error\u003e {\n    let cipher = Aes256Gcm::new(Key::from_slice(key));\n    let nonce: [u8; 12] = OsRng.gen();\n    \n    let ciphertext = cipher\n        .encrypt(Nonce::from_slice(\u0026nonce), plaintext)\n        .map_err(|_| Error::EncryptionFailed)?;\n    \n    // Prepend nonce for storage\n    let mut result = nonce.to_vec();\n    result.extend_from_slice(\u0026ciphertext);\n    Ok(result)\n}\n\n// ✅ CONSTANT-TIME COMPARISONS (prevent timing attacks)\nuse subtle::ConstantTimeEq;\n\nfn verify_mac(expected: \u0026[u8], actual: \u0026[u8]) -\u003e bool {\n    expected.ct_eq(actual).into()  // Always takes same time\n}\n```\n\n---\n\n## Chapter 5: Injection Attacks - When Strings Become Code\n\n### SQL Injection: The Eternal Enemy\n\nEven in Rust, string formatting creates injection vulnerabilities:\n\n```rust\n// ❌ SQL INJECTION\nfn find_user(name: \u0026str) -\u003e Result\u003cUser, Error\u003e {\n    let query = format!(\"SELECT * FROM users WHERE name = '{}'\", name);\n    // name = \"'; DROP TABLE users; --\" = goodbye database\n    database.execute(\u0026query)\n}\n```\n\n```rust\n// ✅ PARAMETERIZED QUERIES\nuse sqlx::PgPool;\n\nasync fn find_user_safe(pool: \u0026PgPool, name: \u0026str) -\u003e Result\u003cUser, Error\u003e {\n    let user = sqlx::query_as!(\n        User,\n        \"SELECT * FROM users WHERE name = $1\",  // $1 is safely escaped\n        name\n    )\n    .fetch_one(pool)\n    .await?;\n    \n    Ok(user)\n}\n```\n\n### Command Injection: Shell Shenanigans\n\n```rust\n// ❌ COMMAND INJECTION\nfn search_logs(pattern: \u0026str) -\u003e Result\u003cString, Error\u003e {\n    let output = Command::new(\"sh\")\n        .arg(\"-c\")\n        .arg(format!(\"grep {} /var/log/app.log\", pattern))  // pattern = \"; rm -rf /\"\n        .output()?;\n    \n    Ok(String::from_utf8(output.stdout)?)\n}\n```\n\n```rust\n// ✅ SAFE: Individual arguments, no shell\nfn search_logs_safe(pattern: \u0026str) -\u003e Result\u003cString, Error\u003e {\n    let output = Command::new(\"grep\")\n        .arg(pattern)  // Treated as literal argument\n        .arg(\"/var/log/app.log\")\n        .output()?;\n    \n    Ok(String::from_utf8(output.stdout)?)\n}\n```\n\n---\n\n## Chapter 6: Async Rust - Concurrency Without Tears\n\n### The Blocking Operation Trap\n\nAsync Rust is fast until you accidentally block the entire runtime:\n\n```rust\n// ❌ BLOCKS ENTIRE RUNTIME\nasync fn hash_password_wrong(password: \u0026str) -\u003e String {\n    // This CPU-intensive work freezes ALL async tasks!\n    expensive_password_hash(password)\n}\n```\n\n```rust\n// ✅ OFFLOAD TO THREAD POOL\nasync fn hash_password_right(password: String) -\u003e Result\u003cString, Error\u003e {\n    let hash = tokio::task::spawn_blocking(move || {\n        expensive_password_hash(\u0026password)\n    })\n    .await\n    .map_err(|_| Error::TaskFailed)?;\n    \n    Ok(hash)\n}\n```\n\n**When to use `spawn_blocking`:**\n- CPU-intensive work (hashing, parsing, compression)\n- Synchronous I/O (file operations, blocking database calls)\n- Any operation taking more than a few milliseconds\n\n### The Lock-Across-Await Deadlock\n\n```rust\n// ❌ DEADLOCK WAITING TO HAPPEN\nasync fn dangerous_pattern(shared: \u0026Mutex\u003cVec\u003cString\u003e\u003e) {\n    let mut data = shared.lock().unwrap();  // Lock acquired\n    data.push(\"item\".to_string());\n    \n    some_async_operation().await;  // ⚠️ Lock held across await!\n    \n    data.push(\"another\".to_string());\n}  // Lock released only here - other tasks blocked!\n```\n\n```rust\n// ✅ SAFE: Release locks before await points\nasync fn safe_pattern(shared: \u0026tokio::sync::Mutex\u003cVec\u003cString\u003e\u003e) {\n    {\n        let mut data = shared.lock().await;\n        data.push(\"item\".to_string());\n    }  // Lock released here\n    \n    some_async_operation().await;  // No lock held\n    \n    {\n        let mut data = shared.lock().await;\n        data.push(\"another\".to_string());\n    }  // Lock released again\n}\n```\n\n### Cancellation Safety: The Hidden Async Danger\n\nEvery `.await` is a potential cancellation point where your future might be dropped:\n\n```rust\n// ❌ NOT CANCELLATION SAFE\nasync fn transfer_funds_unsafe(from: \u0026Account, to: \u0026Account, amount: u64) {\n    from.balance -= amount;  // ⚠️ What if cancelled here?\n    network_commit().await;  // Cancellation point!\n    to.balance += amount;    // Might never execute → money lost!\n}\n```\n\n```rust\n// ✅ CANCELLATION SAFE: Atomic state updates\nasync fn transfer_funds_safe(from: \u0026Account, to: \u0026Account, amount: u64) -\u003e Result\u003c(), Error\u003e {\n    // Do all async work first\n    let transfer_id = prepare_transfer(amount).await?;\n    \n    // Then atomic state update (no cancellation points)\n    tokio::task::spawn_blocking(move || {\n        // This runs to completion\n        from.balance -= amount;\n        to.balance += amount;\n        commit_transfer(transfer_id);\n    }).await?;\n    \n    Ok(())\n}\n```\n\n---\n\n## Chapter 7: Web3 and Smart Contract Security\n\n### The Missing Signer Check (Solana Example)\n\n```rust\n// ❌ AUTHORIZATION BYPASS\npub fn withdraw(ctx: Context\u003cWithdraw\u003e, amount: u64) -\u003e Result\u003c()\u003e {\n    let user_account = \u0026mut ctx.accounts.user_account;\n    // Bug: Never verified that user_account signed this transaction!\n    \n    user_account.balance -= amount;\n    Ok(())\n}\n```\n\n```rust\n// ✅ VERIFY AUTHORIZATION\npub fn withdraw_safe(ctx: Context\u003cWithdraw\u003e, amount: u64) -\u003e Result\u003c()\u003e {\n    let user_account = \u0026mut ctx.accounts.user_account;\n    \n    // Critical: Verify the account holder authorized this\n    require!(user_account.is_signer, ErrorCode::MissingSigner);\n    \n    // Additional safety: Check balance\n    require!(\n        user_account.balance \u003e= amount,\n        ErrorCode::InsufficientFunds\n    );\n    \n    user_account.balance -= amount;\n    Ok(())\n}\n```\n\n### Program Derived Address (PDA) Verification\n\n```rust\n// ❌ TRUSTING USER INPUT\npub fn update_vault(ctx: Context\u003cUpdateVault\u003e) -\u003e Result\u003c()\u003e {\n    let vault = \u0026mut ctx.accounts.vault;\n    // Bug: Attacker could pass a vault they control!\n    vault.amount += 100;\n    Ok(())\n}\n```\n\n```rust\n// ✅ VERIFY PDA OWNERSHIP\npub fn update_vault_safe(ctx: Context\u003cUpdateVault\u003e) -\u003e Result\u003c()\u003e {\n    let vault = \u0026mut ctx.accounts.vault;\n    \n    // Recompute expected PDA\n    let (expected_vault, _bump) = Pubkey::find_program_address(\n        \u0026[b\"vault\", ctx.accounts.user.key().as_ref()],\n        ctx.program_id,\n    );\n    \n    require!(vault.key() == expected_vault, ErrorCode::InvalidVault);\n    \n    vault.amount += 100;\n    Ok(())\n}\n```\n\n### Determinism in Smart Contracts\n\n```rust\n// ❌ NON-DETERMINISTIC (causes consensus failures)\npub fn create_auction(duration_hours: u64) -\u003e Result\u003c()\u003e {\n    let start_time = SystemTime::now()  // Different on each validator!\n        .duration_since(UNIX_EPOCH)\n        .unwrap()\n        .as_secs();\n    Ok(())\n}\n```\n\n```rust\n// ✅ DETERMINISTIC\npub fn create_auction_safe(ctx: Context\u003cCreateAuction\u003e, duration_hours: u64) -\u003e Result\u003c()\u003e {\n    let clock = Clock::get()?;  // Blockchain-provided timestamp\n    let start_time = clock.unix_timestamp as u64;  // Same on all validators\n    Ok(())\n}\n```\n\n---\n\n## Chapter 8: The unsafe Keyword - Handle With Care\n\n### Document Your Contracts\n\nEvery `unsafe` block must explain its safety invariants:\n\n```rust\n// ❌ DANGEROUS: No safety documentation\nunsafe fn write_bytes(ptr: *mut u8, bytes: \u0026[u8]) {\n    std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());\n}\n```\n\n```rust\n// ✅ SAFE: Clear safety contract\n/// Copy bytes to the given pointer.\n///\n/// # Safety\n/// \n/// - `ptr` must be non-null and properly aligned\n/// - `ptr` must point to writable memory for at least `bytes.len()` bytes\n/// - The memory region must not overlap with `bytes`\n/// - No other threads may access the memory region during this call\nunsafe fn write_bytes_safe(ptr: *mut u8, bytes: \u0026[u8]) {\n    debug_assert!(!ptr.is_null(), \"ptr must not be null\");\n    debug_assert!(ptr.is_aligned(), \"ptr must be aligned\");\n    \n    // SAFETY: Caller guarantees all safety requirements above\n    std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len());\n}\n```\n\n### FFI Safety\n\n```rust\nextern \"C\" {\n    fn c_hash_function(input: *const u8, len: usize, output: *mut u8);\n}\n\n// ✅ SAFE FFI WRAPPER\n/// Compute hash using C library.\npub fn hash_bytes(data: \u0026[u8]) -\u003e [u8; 32] {\n    let mut output = [0u8; 32];\n    \n    // SAFETY: \n    // - data.as_ptr() is valid for data.len() bytes\n    // - output.as_mut_ptr() is valid for 32 bytes\n    // - C function documented to write exactly 32 bytes\n    unsafe {\n        c_hash_function(data.as_ptr(), data.len(), output.as_mut_ptr());\n    }\n    \n    output\n}\n```\n\n---\n\n## Chapter 9: Development and Deployment Security\n\n### Dependency Security\n\n```bash\n# ✅ Security audit pipeline\ncargo audit                    # Check for vulnerabilities\ncargo build --release --locked # Use exact dependency versions\ncargo clippy -- -D warnings   # Lint for security issues\n```\n\n### Security-Focused Compiler Settings\n\n```toml\n[profile.release]\noverflow-checks = true     # Catch integer overflows\ndebug-assertions = true    # Keep debug_assert! in release\nstrip = true              # Remove debug symbols\nlto = true                # Link-time optimization\ncodegen-units = 1         # Better optimization\n\n# Security-focused clippy config\n[alias]\nsecure-check = [\n    \"clippy\", \"--all-targets\", \"--all-features\", \"--\",\n    \"-D\", \"clippy::unwrap_used\",\n    \"-D\", \"clippy::expect_used\", \n    \"-D\", \"clippy::indexing_slicing\",\n    \"-D\", \"clippy::panic\",\n]\n```\n\n### Property-Based Testing\n\n```rust\nuse proptest::prelude::*;\n\n// Test security properties, not just happy paths\nproptest! {\n    #[test]\n    fn transfer_never_creates_money(\n        initial_from in 0u64..=1_000_000,\n        initial_to in 0u64..=1_000_000,\n        amount in 0u64..=1_000_000\n    ) {\n        let mut from = Account { balance: initial_from };\n        let mut to = Account { balance: initial_to };\n        let total_before = initial_from + initial_to;\n        \n        let _ = transfer(\u0026mut from, \u0026mut to, amount);\n        \n        let total_after = from.balance + to.balance;\n        prop_assert_eq!(total_before, total_after, \"Money created or destroyed!\");\n    }\n}\n```\n\n---\n\n## Chapter 10: The Security Mindset\n\n### Threat Modeling Questions\n\nFor every function, ask:\n1. **What if the inputs are malicious?**\n2. **What if this is called a million times per second?**\n3. **What if multiple threads call this simultaneously?**\n4. **What's the worst an attacker could do with this function?**\n5. **What assumptions might not hold in production?**\n\n### Defense in Depth\n\n```rust\n// ✅ LAYERED SECURITY\npub fn process_payment(\n    user: \u0026User,\n    amount: TokenAmount,\n    signature: \u0026Signature,\n) -\u003e Result\u003c(), PaymentError\u003e {\n    // Layer 1: Authentication\n    verify_signature(\u0026user.public_key, signature)?;\n    \n    // Layer 2: Authorization\n    user.check_payment_permissions()?;\n    \n    // Layer 3: Input validation\n    if amount.0 == 0 {\n        return Err(PaymentError::ZeroAmount);\n    }\n    \n    // Layer 4: Business rules\n    if amount.0 \u003e user.balance.0 {\n        return Err(PaymentError::InsufficientFunds);\n    }\n    \n    // Layer 5: Rate limiting\n    user.check_rate_limit()?;\n    \n    // Layer 6: Overflow protection\n    let new_balance = user.balance.0\n        .checked_sub(amount.0)\n        .ok_or(PaymentError::ArithmeticError)?;\n    \n    // Finally: Execute\n    user.balance = Balance(new_balance);\n    user.record_payment(amount);\n    \n    Ok(())\n}\n```\n\n---\n\n## The Ultimate Security Checklist\n\nBefore deploying Rust code to production:\n\n### Type Safety ✅\n- [ ] All primitives wrapped in semantic newtypes\n- [ ] No parameter-swapping possible in APIs\n- [ ] Business concepts encoded in types\n\n### Error Handling ✅\n- [ ] No `unwrap()` or `panic!()` in production paths  \n- [ ] All `Result` types properly handled with `?`\n- [ ] Clear error types for different failure modes\n\n### Arithmetic Safety ✅\n- [ ] All money/balance operations use `checked_*`\n- [ ] Overflow checks enabled in release mode\n- [ ] Proper rounding direction for fees vs payouts\n\n### Cryptography ✅\n- [ ] `OsRng` for all security-critical randomness\n- [ ] Secrets wrapped in `Zeroizing` or `secrecy`\n- [ ] No secrets in `Debug` output or logs\n- [ ] Constant-time comparisons for MACs/hashes\n\n### Injection Prevention ✅\n- [ ] All SQL queries parameterized\n- [ ] No shell injection via `format!()` + Command\n- [ ] Input validation and sanitization\n\n### Async Safety ✅\n- [ ] No blocking operations in async contexts\n- [ ] No locks held across `.await` points\n- [ ] Cancellation-safe state updates\n\n### Smart Contract Security ✅\n- [ ] All signers verified before state changes\n- [ ] PDAs recomputed and validated\n- [ ] Deterministic behavior (no `SystemTime::now()`)\n\n### unsafe Code ✅\n- [ ] All `unsafe` blocks documented with safety contracts\n- [ ] Runtime assertions for debug builds\n- [ ] FFI boundaries validated\n\n### Development Security ✅\n- [ ] `cargo audit` passes\n- [ ] Builds use `--locked` flag\n- [ ] Security-focused clippy lints enabled\n- [ ] Property-based tests for invariants\n\n### Deployment Security ✅\n- [ ] Overflow checks enabled in release\n- [ ] Debug symbols stripped\n- [ ] Dependencies pinned and audited\n\n---\n\n## Final Wisdom: The Three Laws of Secure Rust\n\n1. **Make invalid states unrepresentable** - Use the type system to prevent bugs at compile time\n2. **Fail explicitly and gracefully** - Turn potential panics into controlled `Result` types  \n3. **Trust but verify** - Validate all boundaries, especially between safe and unsafe code\n\n## One-Liner for Your Laptop Sticker\n\n*\"Memory safety for free, application security for a price—but that price is just good habits.\"*\n\n---\n\nRemember: Rust gives you a head start on security, but it's not a silver bullet. The most secure code is code that's never written, and the second most secure code is code that's written by developers who think like attackers.\n\nNow go forth and build systems that are not just fast and memory-safe, but actually secure. Your users' money depends on it. 🦀🔒💰\n\n## Contributing \u0026 Contact\n\n- GitHub: \u003chttps://github.com/yevh/rust-security-handbook\u003e  \n- Email: yevhsec1@gmail.com\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyevh%2Frust-security-handbook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyevh%2Frust-security-handbook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyevh%2Frust-security-handbook/lists"}