{"id":50479654,"url":"https://github.com/theroyalwhee0/safename","last_synced_at":"2026-06-01T16:31:39.792Z","repository":{"id":359147243,"uuid":"1129875572","full_name":"theroyalwhee0/safename","owner":"theroyalwhee0","description":"A crate for filename and path validation.","archived":false,"fork":false,"pushed_at":"2026-04-14T03:36:22.000Z","size":124,"stargazers_count":2,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-20T20:24:01.571Z","etag":null,"topics":["filename","path","sanitization","security","validation"],"latest_commit_sha":null,"homepage":"https://docs.rs/safename","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/theroyalwhee0.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-07T17:54:54.000Z","updated_at":"2026-01-07T22:40:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/theroyalwhee0/safename","commit_stats":null,"previous_names":["theroyalwhee0/safename"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/theroyalwhee0/safename","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theroyalwhee0%2Fsafename","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theroyalwhee0%2Fsafename/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theroyalwhee0%2Fsafename/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theroyalwhee0%2Fsafename/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theroyalwhee0","download_url":"https://codeload.github.com/theroyalwhee0/safename/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theroyalwhee0%2Fsafename/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33784625,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-01T02:00:06.963Z","response_time":115,"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":["filename","path","sanitization","security","validation"],"created_at":"2026-06-01T16:31:38.655Z","updated_at":"2026-06-01T16:31:39.787Z","avatar_url":"https://github.com/theroyalwhee0.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# safename\n\nFilename and path validation for security hardening, inspired by David A.\nWheeler's proposed Linux safename LSM.\n\n## Problem\n\nUnix/Linux filesystems allow almost any bytes in filenames, which creates\nsecurity vulnerabilities:\n\n- **Command injection**: Filenames like `-rf` or `--help` are interpreted\n  as flags\n- **Shell expansion**: `~user`, `$HOME`, `*.txt` expand unexpectedly\n- **Terminal attacks**: Control characters can inject escape sequences\n- **Path traversal**: Backslashes normalize to forward slashes on some systems\n- **Delimiter injection**: Colons in PATH, semicolons in scripts\n\nThis library validates and sanitizes filenames to prevent these attacks.\n\n## Usage\n\n```rust\nuse safename::{validate_file, is_file_safe, sanitize_file, SafeNameError};\n\n// Check if a filename is safe\nassert!(is_file_safe(\"normal_file.txt\"));\nassert!(!is_file_safe(\"-rf\"));           // Leading dash\nassert!(!is_file_safe(\"file\\x00name\"));  // Control character\n\n// Get detailed error information\nmatch validate_file(\"-rf\") {\n    Ok(()) =\u003e println!(\"Valid\"),\n    Err(SafeNameError::InvalidByte { index, byte }) =\u003e {\n        println!(\"Invalid byte 0x{:02X} at index {}\", byte, index);\n        // Prints: Invalid byte 0x2D at index 0\n    }\n    Err(SafeNameError::InvalidLength { len, max }) =\u003e {\n        println!(\"Length {} exceeds max {}\", len, max);\n    }\n}\n\n// Sanitize unsafe filenames (returns Result)\nlet safe = sanitize_file(\"-rf\").unwrap();  // Returns b\"_rf\"\n```\n\n### Path validation\n\n```rust\nuse safename::{validate_path, is_path_safe, sanitize_path};\n\nassert!(is_path_safe(\"/home/user/file.txt\"));\nassert!(!is_path_safe(\"/home/-rf\"));  // Component starts with dash\n```\n\n### Custom options\n\n```rust\nuse safename::{validate_file_with_options, FileValidationOptions};\n\nlet opts = FileValidationOptions { max_len: 64, ..Default::default() };\nassert!(validate_file_with_options(b\"short.txt\", \u0026opts).is_ok());\n```\n\n## Default Rules\n\nAlways blocked:\n\n| Bytes       | Description                                          |\n| ----------- | ---------------------------------------------------- |\n| `0x00-0x1F` | Control characters (NUL, tab, newline, escape, etc.) |\n| `/`         | Path separator (cannot appear in filename)           |\n| `0x7F`      | DEL control character                                |\n| `0xFF`      | Invalid UTF-8 leading byte                           |\n\nPosition-dependent:\n\n| Position | Blocked | Reason                             |\n| -------- | ------- | ---------------------------------- |\n| Initial  | `-`     | Interpreted as command-line option |\n| Initial  | `~`     | Shell home directory expansion     |\n| Initial  | space   | Quoting bugs, argument splitting   |\n| Final    | space   | Quoting bugs, argument splitting   |\n\n## Feature Flags\n\nFeatures are organized into tiers:\n\n### `low` (default)\n\nCross-platform safety. Includes:\n\n- `block-colon` - Blocks `:` (PATH injection, /etc/passwd formats)\n- `block-backslash` - Blocks `\\` (path traversal via normalization)\n\n### `require-utf8` (default)\n\nRequires valid UTF-8 encoding. Enabled by default alongside `low`.\n\n### `require-ascii`\n\nAlternative to `require-utf8` for ASCII-only environments. Blocks all bytes \u003e= 0x80.\n\n**Note**: `require-utf8` and `require-ascii` are mutually exclusive (compile error if both enabled).\n\n### `medium`\n\nShell safety without breaking common filenames. Includes `low` plus:\n\n- `block-quotes` - Blocks `\"` and `'`\n- `block-chaining` - Blocks `\u0026`, `;`, `|` (for `\u0026\u0026`, `;`, `||`)\n- `block-redirection` - Blocks `|`, `\u003e`, `\u003c`\n- `block-expansion` - Blocks `$`, `%`, `*`, `?`, `` ` ``\n\n### `high`\n\nMaximum restriction. Includes `medium` plus:\n\n- `block-brackets` - Blocks `(`, `)`, `[`, `]`\n- `block-space` - Blocks spaces everywhere (not just leading/trailing)\n\nNote: These features may break common filenames like `file (copy).txt` or `my document.pdf`.\n\n### Cargo.toml\n\n```toml\n[dependencies]\nsafename = \"0.1\"                          # low (default)\nsafename = { version = \"0.1\", features = [\"medium\"] }\nsafename = { version = \"0.1\", features = [\"high\"] }\nsafename = { version = \"0.1\", default-features = false }  # minimal\nsafename = { version = \"0.1\", default-features = false, features = [\"require-ascii\"] }  # ASCII-only\n```\n\n## Background\n\nInspired by David A. Wheeler's work on safe filenames:\n\n- [Fixing Unix/Linux Filenames](https://dwheeler.com/essays/fixing-unix-linux-filenames.html)\n- [LWN: Restricting pathnames](https://lwn.net/Articles/686021/)\n\n## License\n\nCopyright 2025 Adam Mill\n\nLicensed under the Apache License, Version 2.0. See [LICENSE.txt](LICENSE.txt) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheroyalwhee0%2Fsafename","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftheroyalwhee0%2Fsafename","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftheroyalwhee0%2Fsafename/lists"}