Libmagic-rs security-review
Security review for Rust systems code. Covers memory safety, buffer handling, unsafe code, input validation, resource exhaustion, and supply chain security.
install
source · Clone the upstream repo
git clone https://github.com/EvilBit-Labs/libmagic-rs
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/EvilBit-Labs/libmagic-rs "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/security-review" ~/.claude/skills/evilbit-labs-libmagic-rs-security-review && rm -rf "$T"
manifest:
.claude/skills/security-review/SKILL.mdsource content
Security Review (Rust Systems Code)
When to Activate
- Adding new buffer access or offset resolution code
- Handling untrusted input (magic files, target files)
- Adding or reviewing dependencies
- Modifying parser or evaluator logic
- Before releases or PRs with security-sensitive changes
Security Checklist
1. Memory Safety
Bounds-Checked Buffer Access
// WRONG: Direct indexing can panic let byte = buffer[offset]; // CORRECT: Bounds-checked access let byte = buffer.get(offset).ok_or(MagicError::OutOfBounds)?; // CORRECT: Slice with bounds check let slice = buffer.get(start..end).ok_or(MagicError::OutOfBounds)?;
Safe String Operations
// WRONG: Direct slicing can panic on non-UTF-8 boundaries let rest = &input[2..]; // CORRECT: Use strip_prefix/strip_suffix let rest = input.strip_prefix("0x").unwrap_or(input);
Verification Steps
- All buffer access uses
with bounds checking.get() - No direct indexing (
) on untrusted databuffer[i] - String operations use
/strip_prefix
instead of slicingstrip_suffix - No panicking operations (
,.unwrap()
,.expect()
) in library codepanic!()
2. Unsafe Code Policy
Zero Tolerance
// This is enforced project-wide #![forbid(unsafe_code)]
Verification Steps
-
present in#![forbid(unsafe_code)]lib.rs - No
blocks anywhere in project sourceunsafe - Dependencies with
are vetted (memmap2, byteorder, nom)unsafe -
passes with no vulnerabilitiescargo audit
3. Integer Safety
Overflow Protection
// WRONG: Can overflow silently in release builds let offset = base + adjustment; // CORRECT: Checked arithmetic let offset = base.checked_add(adjustment) .ok_or(MagicError::InvalidOffset { offset: format!("{} + {}", base, adjustment) })?; // CORRECT: Saturating for non-critical paths let score = base_score.saturating_add(bonus);
Verification Steps
- Offset calculations use checked arithmetic
- No implicit integer truncation (e.g.,
)u64 as u32 - Cast operations use
/TryFrom
where overflow is possibletry_into() - Clippy pedantic lints catch suspicious casts
4. Input Validation (Magic Files)
Parser Robustness
// Magic files are untrusted input -- strict validation required fn parse_magic_line(line: &str) -> Result<MagicRule, ParseError> { // Validate line structure before parsing // Return ParseError on invalid syntax, never panic // Skip unrecognized directives gracefully }
Verification Steps
- Parser returns
on invalid syntax, never panicsErr - Deeply nested rules have depth limits
- Unrecognized directives are skipped with warnings
- Malformed offset/type/operator specifications produce clear errors
- Property tests fuzz the parser with arbitrary input
5. Input Validation (Target Files)
File Buffer Safety
// All file access through FileBuffer with bounds checking let fb = FileBuffer::open(path)?; // Size limits prevent resource exhaustion if fb.len() > MAX_FILE_SIZE { return Err(MagicError::FileTooLarge); } // Memory-mapped I/O avoids loading entire file // Bounds checking on every access let data = fb.get(offset, length)?;
Verification Steps
- File size limits enforced before processing
- Memory-mapped I/O used (not reading entire file into memory)
- All
access is bounds-checkedFileBuffer - Truncated/corrupted files handled gracefully
- Zero-length files handled without errors
6. Resource Exhaustion Prevention
CPU Limits
// Evaluation timeout prevents infinite loops let config = EvaluationConfig { timeout: Duration::from_secs(5), max_rules: 10_000, ..Default::default() };
Memory Limits
// Limit collected results to prevent unbounded growth const MAX_MATCHES: usize = 100; if matches.len() >= MAX_MATCHES { break; }
Verification Steps
- Evaluation has configurable timeout
- Maximum rule evaluation count enforced
- Match results bounded
- No unbounded recursion in rule evaluation
- Stack depth limited for nested rules
7. Supply Chain Security
Dependency Audit
# Check for known vulnerabilities cargo audit # Check license compliance cargo deny check # Review dependency tree cargo tree --depth 2
Verification Steps
-
clean (no known vulnerabilities)cargo audit -
passes (license compliance)cargo deny - Minimal dependency surface
-
committed for reproducible buildsCargo.lock - All GitHub Actions pinned to SHA hashes
- Dependabot enabled for automated updates
8. Error Information Leakage
Safe Error Messages
// WRONG: Exposes internal paths or system info Err(format!("Failed to read {}: {}", full_path, system_error)) // CORRECT: Actionable but not leaking Err(MagicError::IoError(std::io::Error::new( std::io::ErrorKind::NotFound, "magic file not found" )))
Verification Steps
- Error messages don't expose absolute file paths to end users
- System-level errors wrapped before surfacing to CLI
- Debug output gated behind
/ verbose flagsRUST_LOG
9. CLI Argument Safety
Path Handling
// clap validates arguments before they reach application code // No shell expansion or command injection possible #[derive(Parser)] struct Args { /// File to identify file: PathBuf, /// Magic file to use #[arg(long)] magic_file: Option<PathBuf>, }
Verification Steps
- CLI arguments parsed by
(no manual parsing)clap - File paths treated as opaque -- no string manipulation
- No shell invocation or command execution from user input
- Symlink handling considered for file access
Pre-Release Security Checklist
-
enforced#![forbid(unsafe_code)] -
passescargo clippy -- -D warnings -
cleancargo audit -
passescargo deny check - All buffer access bounds-checked
- Integer arithmetic overflow-safe
- Property tests cover parser and evaluator
- Resource limits configured
- Error messages reviewed for information leakage
- Dependencies minimized and pinned
- Sigstore attestations configured for release artifacts