thuban 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +63 -0
- package/dist/packages/crucible/rules/code-scanner-core.json +129 -0
- package/dist/packages/crucible/rules/command-injection.json +411 -0
- package/dist/packages/crucible/rules/crypto-misuse.json +35 -0
- package/dist/packages/crucible/rules/deserialization.json +152 -0
- package/dist/packages/crucible/rules/env-injection.json +46 -0
- package/dist/packages/crucible/rules/eval-abuse.json +104 -0
- package/dist/packages/crucible/rules/file-upload.json +46 -0
- package/dist/packages/crucible/rules/hallucination.json +22 -0
- package/dist/packages/crucible/rules/hardcoded-secret.json +397 -0
- package/dist/packages/crucible/rules/hardcoded-url.json +13 -0
- package/dist/packages/crucible/rules/insecure-crypto.json +302 -0
- package/dist/packages/crucible/rules/integer-overflow.json +35 -0
- package/dist/packages/crucible/rules/log-injection.json +33 -0
- package/dist/packages/crucible/rules/mass-assignment.json +112 -0
- package/dist/packages/crucible/rules/open-redirect.json +196 -0
- package/dist/packages/crucible/rules/path-traversal.json +422 -0
- package/dist/packages/crucible/rules/prototype-pollution.json +22 -0
- package/dist/packages/crucible/rules/sql-injection.json +597 -0
- package/dist/packages/crucible/rules/ssrf.json +557 -0
- package/dist/packages/crucible/rules/timing-attack.json +55 -0
- package/dist/packages/crucible/rules/unsafe-block.json +24 -0
- package/dist/packages/crucible/rules/xss.json +641 -0
- package/dist/packages/crucible/rules/xxe.json +66 -0
- package/dist/packages/crucible/rules/yaml-deserialization.json +22 -0
- package/dist/packages/crucible/rules/yaml-injection.json +22 -0
- package/dist/packages/scanner/executive-report.js +1 -1
- package/dist/packages/scanner/hallucination-detector.js +1 -1
- package/dist/packages/scanner/secret-scanner.js +1 -1
- package/package.json +7 -4
- package/dist/packages/crucible/seeds/python/seed-021 3.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-022 3.py +0 -34
- package/dist/packages/crucible/seeds/python/seed-023 3.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-024 3.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-025 3.py +0 -40
- package/dist/packages/crucible/seeds/python/seed-026 3.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-027 3.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-028 3.py +0 -42
- package/dist/packages/crucible/seeds/python/seed-030 3.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-031 3.py +0 -34
- package/dist/packages/crucible/seeds/python/seed-036 3.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-037 3.py +0 -41
- package/dist/packages/crucible/seeds/python/seed-038 3.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-039 3.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-040 3.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-041 3.py +0 -37
- package/dist/packages/crucible/seeds/python/seed-042 3.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-043 3.py +0 -32
- package/dist/packages/crucible/seeds/python/seed-044 3.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-045 3.py +0 -36
- package/dist/packages/crucible/seeds/python/seed-046 3.py +0 -33
- package/dist/packages/crucible/seeds/python/seed-047 3.py +0 -44
- package/dist/packages/crucible/seeds/python/seed-048 3.py +0 -35
- package/dist/packages/crucible/seeds/python/seed-049 3.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-050 3.py +0 -39
- package/dist/packages/crucible/seeds/python/seed-051 3.py +0 -38
- package/dist/packages/crucible/seeds/python/seed-052 3.py +0 -41
- package/dist/packages/crucible/seeds/ruby/seed-001 3.rb +0 -15
- package/dist/packages/crucible/seeds/ruby/seed-002 3.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-003 3.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-004 3.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-005 3.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-006 3.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-007 3.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-008 3.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-009 3.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-010 3.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-011 3.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-012 3.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-013 3.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-014 3.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-015 3.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-016 3.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-017 3.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-018 3.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-019 3.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-020 3.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-021 3.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-022 3.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-023 3.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-024 3.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-025 3.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-026 3.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-027 3.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-028 3.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-029 3.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-030 3.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-031 3.rb +0 -17
- package/dist/packages/crucible/seeds/ruby/seed-032 3.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-033 3.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-034 3.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-035 3.rb +0 -19
- package/dist/packages/crucible/seeds/ruby/seed-036 3.rb +0 -18
- package/dist/packages/crucible/seeds/ruby/seed-037 3.rb +0 -21
- package/dist/packages/crucible/seeds/ruby/seed-038 3.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-039 3.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-040 3.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-041 3.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-042 3.rb +0 -25
- package/dist/packages/crucible/seeds/ruby/seed-043 3.rb +0 -23
- package/dist/packages/crucible/seeds/ruby/seed-044 3.rb +0 -16
- package/dist/packages/crucible/seeds/ruby/seed-045 3.rb +0 -22
- package/dist/packages/crucible/seeds/ruby/seed-046 3.rb +0 -27
- package/dist/packages/crucible/seeds/ruby/seed-047 3.rb +0 -26
- package/dist/packages/crucible/seeds/ruby/seed-048 3.rb +0 -24
- package/dist/packages/crucible/seeds/ruby/seed-049 3.rb +0 -20
- package/dist/packages/crucible/seeds/ruby/seed-050 3.rb +0 -27
- package/dist/packages/crucible/seeds/rust/seed-001 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-002 3.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-003 3.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-004 3.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-005 3.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-006 3.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-007 3.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-008 3.rs +0 -19
- package/dist/packages/crucible/seeds/rust/seed-009 3.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-010 3.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-011 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-012 3.rs +0 -31
- package/dist/packages/crucible/seeds/rust/seed-013 3.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-014 3.rs +0 -30
- package/dist/packages/crucible/seeds/rust/seed-015 3.rs +0 -33
- package/dist/packages/crucible/seeds/rust/seed-016 3.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-017 3.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-018 3.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-019 3.rs +0 -36
- package/dist/packages/crucible/seeds/rust/seed-020 3.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-021 3.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-022 3.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-023 3.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-024 3.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-025 3.rs +0 -29
- package/dist/packages/crucible/seeds/rust/seed-026 3.rs +0 -23
- package/dist/packages/crucible/seeds/rust/seed-027 3.rs +0 -24
- package/dist/packages/crucible/seeds/rust/seed-028 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-029 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-030 3.rs +0 -30
- package/dist/packages/crucible/seeds/rust/seed-031 3.rs +0 -22
- package/dist/packages/crucible/seeds/rust/seed-032 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-033 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-034 3.rs +0 -20
- package/dist/packages/crucible/seeds/rust/seed-035 3.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-036 3.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-037 3.rs +0 -31
- package/dist/packages/crucible/seeds/rust/seed-038 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-039 3.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-040 3.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-041 3.rs +0 -32
- package/dist/packages/crucible/seeds/rust/seed-042 3.rs +0 -27
- package/dist/packages/crucible/seeds/rust/seed-043 3.rs +0 -29
- package/dist/packages/crucible/seeds/rust/seed-044 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-045 3.rs +0 -28
- package/dist/packages/crucible/seeds/rust/seed-046 3.rs +0 -25
- package/dist/packages/crucible/seeds/rust/seed-047 3.rs +0 -34
- package/dist/packages/crucible/seeds/rust/seed-048 3.rs +0 -21
- package/dist/packages/crucible/seeds/rust/seed-049 3.rs +0 -26
- package/dist/packages/crucible/seeds/rust/seed-050 3.rs +0 -23
- package/dist/packages/crucible/seeds/ts/seed-001 3.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-002 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-003 3.ts +0 -28
- package/dist/packages/crucible/seeds/ts/seed-004 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-005 3.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-006 3.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-007 3.ts +0 -28
- package/dist/packages/crucible/seeds/ts/seed-008 3.ts +0 -40
- package/dist/packages/crucible/seeds/ts/seed-009 3.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-010 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-011 3.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-012 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-013 3.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-014 3.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-015 3.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-016 3.ts +0 -37
- package/dist/packages/crucible/seeds/ts/seed-017 3.ts +0 -44
- package/dist/packages/crucible/seeds/ts/seed-018 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-019 3.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-020 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-021 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-022 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-023 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-024 3.ts +0 -35
- package/dist/packages/crucible/seeds/ts/seed-025 3.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-026 3.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-027 3.ts +0 -30
- package/dist/packages/crucible/seeds/ts/seed-028 3.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-029 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-030 3.ts +0 -37
- package/dist/packages/crucible/seeds/ts/seed-031 3.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-032 3.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-033 3.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-034 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-035 3.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-036 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-037 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-038 3.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-039 3.ts +0 -35
- package/dist/packages/crucible/seeds/ts/seed-040 3.ts +0 -31
- package/dist/packages/crucible/seeds/ts/seed-041 3.ts +0 -29
- package/dist/packages/crucible/seeds/ts/seed-042 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-043 3.ts +0 -32
- package/dist/packages/crucible/seeds/ts/seed-044 3.ts +0 -36
- package/dist/packages/crucible/seeds/ts/seed-045 3.ts +0 -39
- package/dist/packages/crucible/seeds/ts/seed-046 3.ts +0 -41
- package/dist/packages/crucible/seeds/ts/seed-047 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-048 3.ts +0 -33
- package/dist/packages/crucible/seeds/ts/seed-049 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-050 3.ts +0 -41
- package/dist/packages/crucible/seeds/ts/seed-051 3.ts +0 -34
- package/dist/packages/crucible/seeds/ts/seed-052 3.ts +0 -36
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: path_traversal
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: fs::read with user-supplied path — no canonicalization or prefix check
|
|
6
|
-
|
|
7
|
-
use std::fs;
|
|
8
|
-
use std::path::Path;
|
|
9
|
-
|
|
10
|
-
pub fn read_file(base_dir: &str, filename: &str) -> Result<Vec<u8>, std::io::Error> {
|
|
11
|
-
let path = format!("{}/{}", base_dir, filename);
|
|
12
|
-
fs::read(&path)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn get_file_content(user_path: &str) -> String {
|
|
16
|
-
let full_path = format!("/var/app/uploads/{}", user_path);
|
|
17
|
-
fs::read_to_string(&full_path).unwrap_or_default()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub fn file_exists(base: &str, name: &str) -> bool {
|
|
21
|
-
Path::new(&format!("{}/{}", base, name)).exists()
|
|
22
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: path_traversal
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Axum handler reads file from path parameter without validation
|
|
6
|
-
|
|
7
|
-
use axum::{extract::Path, response::IntoResponse};
|
|
8
|
-
use std::fs;
|
|
9
|
-
|
|
10
|
-
pub async fn serve_file(Path(filename): Path<String>) -> impl IntoResponse {
|
|
11
|
-
let path = format!("/app/static/{}", filename);
|
|
12
|
-
match fs::read_to_string(&path) {
|
|
13
|
-
Ok(content) => (axum::http::StatusCode::OK, content),
|
|
14
|
-
Err(_) => (axum::http::StatusCode::NOT_FOUND, "Not found".to_string()),
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
pub async fn download_resource(Path((dir, file)): Path<(String, String)>) -> impl IntoResponse {
|
|
19
|
-
let full_path = format!("/data/{}/{}", dir, file);
|
|
20
|
-
match fs::read(&full_path) {
|
|
21
|
-
Ok(bytes) => (axum::http::StatusCode::OK, format!("{} bytes", bytes.len())),
|
|
22
|
-
Err(e) => (axum::http::StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: path_traversal
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Zip extraction writes to path from ZipFile entry without canonicalization
|
|
6
|
-
|
|
7
|
-
use std::fs::{self, File};
|
|
8
|
-
use std::io;
|
|
9
|
-
use std::path::Path;
|
|
10
|
-
use zip::ZipArchive;
|
|
11
|
-
|
|
12
|
-
pub fn extract_zip(zip_path: &str, dest: &str) -> io::Result<()> {
|
|
13
|
-
let file = File::open(zip_path)?;
|
|
14
|
-
let mut archive = ZipArchive::new(file)?;
|
|
15
|
-
for i in 0..archive.len() {
|
|
16
|
-
let mut entry = archive.by_index(i)?;
|
|
17
|
-
let out_path = Path::new(dest).join(entry.name());
|
|
18
|
-
if entry.is_dir() {
|
|
19
|
-
fs::create_dir_all(&out_path)?;
|
|
20
|
-
} else {
|
|
21
|
-
if let Some(parent) = out_path.parent() {
|
|
22
|
-
fs::create_dir_all(parent)?;
|
|
23
|
-
}
|
|
24
|
-
let mut outfile = File::create(&out_path)?;
|
|
25
|
-
io::copy(&mut entry, &mut outfile)?;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
Ok(())
|
|
29
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: path_traversal
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: File write to user-controlled path without restricting to base directory
|
|
6
|
-
|
|
7
|
-
use std::fs;
|
|
8
|
-
|
|
9
|
-
pub fn write_report(report_name: &str, content: &str) -> Result<(), std::io::Error> {
|
|
10
|
-
let path = format!("/var/reports/{}", report_name);
|
|
11
|
-
fs::write(&path, content)?;
|
|
12
|
-
Ok(())
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn save_template(template_id: &str, subdir: &str, data: &[u8]) -> bool {
|
|
16
|
-
let full_path = format!("/app/templates/{}/{}.tmpl", subdir, template_id);
|
|
17
|
-
fs::write(&full_path, data).is_ok()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub fn cache_response(cache_key: &str, data: &str) -> bool {
|
|
21
|
-
let path = format!("/tmp/cache/{}", cache_key);
|
|
22
|
-
fs::write(path, data).is_ok()
|
|
23
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: path_traversal
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Config file loaded from user-controlled path — arbitrary file read
|
|
6
|
-
|
|
7
|
-
use std::fs;
|
|
8
|
-
use serde_json::Value;
|
|
9
|
-
|
|
10
|
-
pub fn load_config(config_name: &str) -> Value {
|
|
11
|
-
let path = format!("/etc/app/configs/{}", config_name);
|
|
12
|
-
let content = fs::read_to_string(&path).unwrap_or_else(|_| "{}".to_string());
|
|
13
|
-
serde_json::from_str(&content).unwrap_or(Value::Null)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
pub fn load_plugin_manifest(plugin_id: &str) -> String {
|
|
17
|
-
let manifest_path = format!("./plugins/{}/manifest.json", plugin_id);
|
|
18
|
-
fs::read_to_string(manifest_path).unwrap_or_default()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
pub fn read_user_template(user_id: &str, template_name: &str) -> String {
|
|
22
|
-
let path = format!("/data/users/{}/templates/{}", user_id, template_name);
|
|
23
|
-
fs::read_to_string(path).unwrap_or_default()
|
|
24
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: path_traversal
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Directory listing served from user-controlled subdirectory
|
|
6
|
-
|
|
7
|
-
use std::fs;
|
|
8
|
-
|
|
9
|
-
pub fn list_directory(base: &str, subdir: &str) -> Vec<String> {
|
|
10
|
-
let path = format!("{}/{}", base, subdir);
|
|
11
|
-
match fs::read_dir(&path) {
|
|
12
|
-
Ok(entries) => entries
|
|
13
|
-
.filter_map(|e| e.ok())
|
|
14
|
-
.map(|e| e.file_name().to_string_lossy().to_string())
|
|
15
|
-
.collect(),
|
|
16
|
-
Err(_) => vec![],
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub fn serve_directory(root: &str, user_path: &str) -> String {
|
|
21
|
-
let full = format!("{}/{}", root, user_path);
|
|
22
|
-
fs::read_dir(&full)
|
|
23
|
-
.map(|rd| rd.count().to_string())
|
|
24
|
-
.unwrap_or_else(|e| e.to_string())
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: integer_overflow
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Explicit unchecked arithmetic that wraps on overflow in release mode
|
|
6
|
-
|
|
7
|
-
pub fn calculate_offset(index: usize, stride: usize) -> usize {
|
|
8
|
-
index * stride
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
pub fn buffer_size(width: u32, height: u32, channels: u32) -> u32 {
|
|
12
|
-
width * height * channels
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn total_price(unit_price: u32, quantity: u32) -> u32 {
|
|
16
|
-
unit_price * quantity
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn encode_coords(x: i32, y: i32) -> i64 {
|
|
20
|
-
(x as i64) * 100000 + (y as i64)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pub fn as_usize_unchecked(n: i64) -> usize {
|
|
24
|
-
n as usize
|
|
25
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: integer_overflow
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Cast truncation — u64 to u32/u16/u8 silently drops high bits
|
|
6
|
-
|
|
7
|
-
pub fn truncate_to_u8(val: u64) -> u8 {
|
|
8
|
-
val as u8
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
pub fn truncate_to_u16(val: u64) -> u16 {
|
|
12
|
-
val as u16
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn index_from_user_input(input: i64) -> usize {
|
|
16
|
-
input as usize
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn packet_len_from_i32(len: i32) -> usize {
|
|
20
|
-
len as usize
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pub fn compress_timestamp(ts: u64) -> u32 {
|
|
24
|
-
ts as u32
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
pub fn negate_unsigned(n: u32) -> u32 {
|
|
28
|
-
let signed = n as i32;
|
|
29
|
-
(-signed) as u32
|
|
30
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: integer_overflow
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Allocation size computed from untrusted user input — potential OOM / overflow
|
|
6
|
-
|
|
7
|
-
use std::alloc::{alloc, Layout};
|
|
8
|
-
|
|
9
|
-
pub fn allocate_buffer(user_size: u32, element_size: u32) -> Vec<u8> {
|
|
10
|
-
let total = (user_size * element_size) as usize;
|
|
11
|
-
vec![0u8; total]
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
pub unsafe fn raw_alloc(count: usize, item_size: usize) -> *mut u8 {
|
|
15
|
-
let size = count * item_size;
|
|
16
|
-
let layout = Layout::from_size_align_unchecked(size, 8);
|
|
17
|
-
alloc(layout)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub fn string_repeat(s: &str, n: u32) -> String {
|
|
21
|
-
s.repeat(n as usize)
|
|
22
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: integer_overflow
|
|
3
|
-
// severity: medium
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Signed integer arithmetic without overflow check — negative length risk
|
|
6
|
-
|
|
7
|
-
pub fn calculate_remaining(total: i32, used: i32) -> i32 {
|
|
8
|
-
total - used
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
pub fn chunk_count(data_len: i32, chunk_size: i32) -> i32 {
|
|
12
|
-
(data_len + chunk_size - 1) / chunk_size
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn ring_buffer_advance(pos: u32, step: u32, capacity: u32) -> u32 {
|
|
16
|
-
(pos + step) % capacity
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn decode_delta(base: u32, delta: i32) -> u32 {
|
|
20
|
-
(base as i32 + delta) as u32
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pub fn safe_subtract(a: u32, b: u32) -> u32 {
|
|
24
|
-
a - b
|
|
25
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: integer_overflow
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Array index from user input without bounds check — potential panic or OOM
|
|
6
|
-
|
|
7
|
-
pub fn get_element(data: &[u8], index: usize) -> u8 {
|
|
8
|
-
data[index]
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
pub fn set_element(data: &mut Vec<u8>, index: usize, value: u8) {
|
|
12
|
-
data[index] = value;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub fn read_matrix(matrix: &[Vec<i32>], row: usize, col: usize) -> i32 {
|
|
16
|
-
matrix[row][col]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn sum_range(data: &[i64], start: usize, end: usize) -> i64 {
|
|
20
|
-
data[start..end].iter().sum()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pub fn nth_element(data: &[String], n: usize) -> &str {
|
|
24
|
-
&data[n]
|
|
25
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: ssrf
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: reqwest::get called with user-controlled URL — SSRF
|
|
6
|
-
|
|
7
|
-
use reqwest;
|
|
8
|
-
|
|
9
|
-
pub async fn fetch_url(user_url: &str) -> Result<String, reqwest::Error> {
|
|
10
|
-
let response = reqwest::get(user_url).await?;
|
|
11
|
-
let body = response.text().await?;
|
|
12
|
-
Ok(body)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
pub async fn proxy_request(target: &str) -> String {
|
|
16
|
-
reqwest::get(target)
|
|
17
|
-
.await
|
|
18
|
-
.and_then(|r| async { r.text().await }.await.map_err(Into::into))
|
|
19
|
-
.unwrap_or_default()
|
|
20
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: ssrf
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Axum endpoint fetches user-supplied URL server-side — open proxy / SSRF
|
|
6
|
-
|
|
7
|
-
use axum::{extract::Query, response::IntoResponse};
|
|
8
|
-
use reqwest::Client;
|
|
9
|
-
use std::collections::HashMap;
|
|
10
|
-
|
|
11
|
-
pub async fn proxy_endpoint(Query(params): Query<HashMap<String, String>>) -> impl IntoResponse {
|
|
12
|
-
let url = params.get("url").cloned().unwrap_or_default();
|
|
13
|
-
let client = Client::new();
|
|
14
|
-
match client.get(&url).send().await {
|
|
15
|
-
Ok(resp) => resp.text().await.unwrap_or_default(),
|
|
16
|
-
Err(e) => format!("Error: {}", e),
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub async fn webhook_relay(Query(params): Query<HashMap<String, String>>) -> impl IntoResponse {
|
|
21
|
-
let callback = params.get("callback").cloned().unwrap_or_default();
|
|
22
|
-
let _ = Client::new()
|
|
23
|
-
.post(&callback)
|
|
24
|
-
.json(&serde_json::json!({"status": "ok"}))
|
|
25
|
-
.send()
|
|
26
|
-
.await;
|
|
27
|
-
"Triggered"
|
|
28
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: ssrf
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: URL constructed from user-supplied hostname and path — SSRF
|
|
6
|
-
|
|
7
|
-
use reqwest::Client;
|
|
8
|
-
|
|
9
|
-
pub async fn check_endpoint(host: &str, port: u16, path: &str) -> bool {
|
|
10
|
-
let url = format!("http://{}:{}{}", host, port, path);
|
|
11
|
-
Client::new().get(&url).send().await.is_ok()
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
pub async fn fetch_avatar(base_url: &str, user_id: &str) -> Vec<u8> {
|
|
15
|
-
let url = format!("{}/avatars/{}.png", base_url, user_id);
|
|
16
|
-
reqwest::get(&url)
|
|
17
|
-
.await
|
|
18
|
-
.and_then(|r| async { r.bytes().await }.await.map_err(Into::into))
|
|
19
|
-
.map(|b| b.to_vec())
|
|
20
|
-
.unwrap_or_default()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pub async fn import_data(source_url: &str) -> serde_json::Value {
|
|
24
|
-
let text = reqwest::get(source_url).await.unwrap().text().await.unwrap();
|
|
25
|
-
serde_json::from_str(&text).unwrap_or(serde_json::Value::Null)
|
|
26
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: ssrf
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Image URL fetched server-side from user POST body — SSRF via metadata endpoint
|
|
6
|
-
|
|
7
|
-
use reqwest::Client;
|
|
8
|
-
use serde::Deserialize;
|
|
9
|
-
|
|
10
|
-
#[derive(Deserialize)]
|
|
11
|
-
pub struct ImageRequest {
|
|
12
|
-
pub url: String,
|
|
13
|
-
pub format: String,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
pub async fn download_and_process(req: ImageRequest) -> Vec<u8> {
|
|
17
|
-
let client = Client::new();
|
|
18
|
-
let bytes = client
|
|
19
|
-
.get(&req.url)
|
|
20
|
-
.send()
|
|
21
|
-
.await
|
|
22
|
-
.unwrap()
|
|
23
|
-
.bytes()
|
|
24
|
-
.await
|
|
25
|
-
.unwrap();
|
|
26
|
-
bytes.to_vec()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
pub async fn get_og_metadata(page_url: &str) -> String {
|
|
30
|
-
reqwest::get(page_url).await.unwrap().text().await.unwrap()
|
|
31
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: ssrf
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: DNS rebinding-vulnerable health check using user-supplied host
|
|
6
|
-
|
|
7
|
-
use reqwest::Client;
|
|
8
|
-
use std::time::Duration;
|
|
9
|
-
|
|
10
|
-
pub async fn health_check(host: &str) -> serde_json::Value {
|
|
11
|
-
let url = format!("http://{}/health", host);
|
|
12
|
-
let client = Client::builder()
|
|
13
|
-
.timeout(Duration::from_secs(5))
|
|
14
|
-
.build()
|
|
15
|
-
.unwrap();
|
|
16
|
-
match client.get(&url).send().await {
|
|
17
|
-
Ok(resp) => resp.json().await.unwrap_or(serde_json::Value::Null),
|
|
18
|
-
Err(_) => serde_json::json!({"status": "unreachable"}),
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
pub async fn resolve_and_fetch(domain: &str, endpoint: &str) -> String {
|
|
23
|
-
let url = format!("https://{}{}", domain, endpoint);
|
|
24
|
-
reqwest::get(&url).await.unwrap().text().await.unwrap()
|
|
25
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: race_condition
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Arc<Mutex<>> lock held across await point — potential deadlock
|
|
6
|
-
|
|
7
|
-
use std::sync::{Arc, Mutex};
|
|
8
|
-
use tokio::time::{sleep, Duration};
|
|
9
|
-
|
|
10
|
-
pub struct SharedState {
|
|
11
|
-
data: Arc<Mutex<Vec<String>>>,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
impl SharedState {
|
|
15
|
-
pub async fn add_and_process(&self, item: String) {
|
|
16
|
-
let mut guard = self.data.lock().unwrap();
|
|
17
|
-
guard.push(item);
|
|
18
|
-
sleep(Duration::from_millis(100)).await;
|
|
19
|
-
println!("Processed: {:?}", guard.last());
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
pub async fn read_then_write(&self, key: String) -> Option<String> {
|
|
23
|
-
let guard = self.data.lock().unwrap();
|
|
24
|
-
let found = guard.iter().find(|s| s.starts_with(&key)).cloned();
|
|
25
|
-
sleep(Duration::from_secs(1)).await;
|
|
26
|
-
found
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: race_condition
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Check-then-act race condition on shared file resource
|
|
6
|
-
|
|
7
|
-
use std::fs;
|
|
8
|
-
use std::path::Path;
|
|
9
|
-
|
|
10
|
-
pub fn create_if_not_exists(path: &str, content: &str) -> bool {
|
|
11
|
-
if !Path::new(path).exists() {
|
|
12
|
-
fs::write(path, content).is_ok()
|
|
13
|
-
} else {
|
|
14
|
-
false
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
pub fn atomic_counter_increment(path: &str) -> u64 {
|
|
19
|
-
let current: u64 = fs::read_to_string(path)
|
|
20
|
-
.unwrap_or("0".to_string())
|
|
21
|
-
.trim()
|
|
22
|
-
.parse()
|
|
23
|
-
.unwrap_or(0);
|
|
24
|
-
let next = current + 1;
|
|
25
|
-
fs::write(path, next.to_string()).unwrap();
|
|
26
|
-
next
|
|
27
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: race_condition
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Unsafe impl Send for type containing raw pointer — data race
|
|
6
|
-
|
|
7
|
-
use std::ptr;
|
|
8
|
-
|
|
9
|
-
pub struct RawBuffer {
|
|
10
|
-
ptr: *mut u8,
|
|
11
|
-
len: usize,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
unsafe impl Send for RawBuffer {}
|
|
15
|
-
unsafe impl Sync for RawBuffer {}
|
|
16
|
-
|
|
17
|
-
impl RawBuffer {
|
|
18
|
-
pub fn new(size: usize) -> Self {
|
|
19
|
-
let mut data = vec![0u8; size];
|
|
20
|
-
let ptr = data.as_mut_ptr();
|
|
21
|
-
std::mem::forget(data);
|
|
22
|
-
RawBuffer { ptr, len: size }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
pub fn write_at(&self, offset: usize, value: u8) {
|
|
26
|
-
unsafe { ptr::write(self.ptr.add(offset), value) }
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
pub fn read_at(&self, offset: usize) -> u8 {
|
|
30
|
-
unsafe { ptr::read(self.ptr.add(offset)) }
|
|
31
|
-
}
|
|
32
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: race_condition
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Multiple threads access static mut without synchronization
|
|
6
|
-
|
|
7
|
-
static mut GLOBAL_COUNTER: u64 = 0;
|
|
8
|
-
static mut INITIALIZED: bool = false;
|
|
9
|
-
|
|
10
|
-
pub fn increment_global() {
|
|
11
|
-
unsafe {
|
|
12
|
-
GLOBAL_COUNTER += 1;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
pub fn get_global() -> u64 {
|
|
17
|
-
unsafe { GLOBAL_COUNTER }
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
pub fn initialize_once(value: u64) {
|
|
21
|
-
unsafe {
|
|
22
|
-
if !INITIALIZED {
|
|
23
|
-
GLOBAL_COUNTER = value;
|
|
24
|
-
INITIALIZED = true;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: race_condition
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Mutex poisoning ignored with unwrap — may expose partial state
|
|
6
|
-
|
|
7
|
-
use std::sync::{Arc, Mutex};
|
|
8
|
-
use std::thread;
|
|
9
|
-
|
|
10
|
-
pub fn parallel_updates(shared: Arc<Mutex<Vec<i32>>>, items: Vec<i32>) {
|
|
11
|
-
let handles: Vec<_> = items.into_iter().map(|item| {
|
|
12
|
-
let shared = Arc::clone(&shared);
|
|
13
|
-
thread::spawn(move || {
|
|
14
|
-
let mut guard = shared.lock().unwrap();
|
|
15
|
-
guard.push(item);
|
|
16
|
-
if item == 42 {
|
|
17
|
-
panic!("Special case panic — poisons the Mutex");
|
|
18
|
-
}
|
|
19
|
-
})
|
|
20
|
-
}).collect();
|
|
21
|
-
|
|
22
|
-
for h in handles {
|
|
23
|
-
let _ = h.join();
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
pub fn read_poisoned(shared: Arc<Mutex<Vec<i32>>>) -> Vec<i32> {
|
|
28
|
-
shared.lock().unwrap().clone()
|
|
29
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: crypto_misuse
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: MD5 crate used for password or data integrity hashing
|
|
6
|
-
|
|
7
|
-
use md5;
|
|
8
|
-
|
|
9
|
-
pub fn hash_password(password: &str) -> String {
|
|
10
|
-
let digest = md5::compute(password.as_bytes());
|
|
11
|
-
format!("{:x}", digest)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
pub fn hash_with_salt(password: &str, username: &str) -> String {
|
|
15
|
-
let input = format!("{}:{}", username, password);
|
|
16
|
-
format!("{:x}", md5::compute(input.as_bytes()))
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pub fn verify_password(password: &str, stored_hash: &str) -> bool {
|
|
20
|
-
hash_password(password) == stored_hash
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
pub fn generate_cache_key(data: &str) -> String {
|
|
24
|
-
format!("{:x}", md5::compute(data))
|
|
25
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: crypto_misuse
|
|
3
|
-
// severity: critical
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: Custom XOR cipher implementation — homegrown crypto
|
|
6
|
-
|
|
7
|
-
pub fn xor_encrypt(data: &[u8], key: &[u8]) -> Vec<u8> {
|
|
8
|
-
data.iter()
|
|
9
|
-
.zip(key.iter().cycle())
|
|
10
|
-
.map(|(d, k)| d ^ k)
|
|
11
|
-
.collect()
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
pub fn xor_decrypt(ciphertext: &[u8], key: &[u8]) -> Vec<u8> {
|
|
15
|
-
xor_encrypt(ciphertext, key)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
pub fn rot13(input: &str) -> String {
|
|
19
|
-
input.chars().map(|c| match c {
|
|
20
|
-
'a'..='m' | 'A'..='M' => (c as u8 + 13) as char,
|
|
21
|
-
'n'..='z' | 'N'..='Z' => (c as u8 - 13) as char,
|
|
22
|
-
_ => c,
|
|
23
|
-
}).collect()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
pub fn caesar_cipher(text: &str, shift: u8) -> String {
|
|
27
|
-
text.bytes().map(|b| ((b - b'a' + shift) % 26 + b'a') as char).collect()
|
|
28
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// [CRUCIBLE-SEED]
|
|
2
|
-
// category: crypto_misuse
|
|
3
|
-
// severity: high
|
|
4
|
-
// language: rust
|
|
5
|
-
// expected: rand::random used for security token generation — not cryptographically secure
|
|
6
|
-
|
|
7
|
-
use rand::Rng;
|
|
8
|
-
|
|
9
|
-
pub fn generate_session_token() -> String {
|
|
10
|
-
let mut rng = rand::thread_rng();
|
|
11
|
-
(0..32).map(|_| format!("{:02x}", rng.gen::<u8>())).collect()
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
pub fn generate_otp() -> u32 {
|
|
15
|
-
rand::thread_rng().gen_range(100000..999999)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
pub fn generate_api_key(prefix: &str) -> String {
|
|
19
|
-
let mut rng = rand::thread_rng();
|
|
20
|
-
let suffix: String = (0..24).map(|_| {
|
|
21
|
-
let idx = rng.gen_range(0..36usize);
|
|
22
|
-
"abcdefghijklmnopqrstuvwxyz0123456789".chars().nth(idx).unwrap()
|
|
23
|
-
}).collect();
|
|
24
|
-
format!("{}_{}", prefix, suffix)
|
|
25
|
-
}
|