Skip to content

fix(security): prevent 9 panic/OOM vectors in VRL runtime (batch J) - #7

Open
JuanMantica45 wants to merge 1 commit into
Sentinel-One:mainfrom
JuanMantica45:fix-obe-batch-j-vrl-panics
Open

fix(security): prevent 9 panic/OOM vectors in VRL runtime (batch J)#7
JuanMantica45 wants to merge 1 commit into
Sentinel-One:mainfrom
JuanMantica45:fix-obe-batch-j-vrl-panics

Conversation

@JuanMantica45

Copy link
Copy Markdown

Summary

Closes OBE-10722, OBE-10723, OBE-10724, OBE-10727, OBE-10731, OBE-10733, OBE-10734, OBE-10735, OBE-10743.

Batch J of the security audit identified 9 exploitable panic/DoS paths in the VRL runtime, all reachable from untrusted event data or operator-authored programs. This PR fixes all of them with minimal surgical changes.

Ticket Location Vulnerability Fix
OBE-10722 stdlib/find.rs Negative from wraps to usize::MAXregex::find_at panics when offset > haystack.len() Clamp from.max(0) before cast; add bounds check in find_regex_in_str
OBE-10723 stdlib/format_number.rs Decimal::from_f64(*v).expect("not NaN") panics on ±∞ and floats > 7.9e28 (NotNan permits ∞) Replace with fallible .ok_or_else(...)? returning a VRL error
OBE-10724 stdlib/format_number.rs scale: i64 as usize + unbounded push('0') loop → OOM for large/negative scale Reject negative scale; cap at 1024; change type_def to fallible()
OBE-10727 compiler/value/arithmetic.rs NotNan::mul/add/rem panic when result is NaN (e.g. ∞ * 0, ∞ + -∞, ∞ % ∞); try_sub was already fixed (#1186) but mul/add/rem were not Add safe_mul, safe_add, safe_rem mirroring the existing safe_sub pattern
OBE-10731 parsing/xml.rs Single-child path calls node.children().next() without filtering; a Comment/PI child reaches process_node_ => unreachable!() Filter single-child path to element/text nodes only
OBE-10733 stdlib/starts_with.rs Hand-rolled Chars::next uses utf8_width::get_width returning 0 for stray bytes → slice of length 0 → from_utf8("") = Ok"".chars().next() = None.unwrap() panics Handle width == 0 and truncated sequences as error bytes; fix off-by-one in Err arm
OBE-10734 parser/lex.rs Lexer's escape_code accepts \} but unescape_string_literal has no b'}' arm → hits unimplemented!() Add b'}' => '}' arm
OBE-10735 value/value/crud/mod.rs + insert.rs insert_value pads with Value::Null up to arbitrary index with no cap → OOM; Vec::with_capacity(index+1) also uncapped Cap index at ±32 768; cap with_capacity to the same limit
OBE-10743 stdlib/parse_grok.rs pattern.match_against uses external grok crate whose Oniguruma regex engine panics on retry-limit exhaustion; parse_groks has catch_unwind but parse_grok (singular) does not Wrap match_against in std::panic::catch_unwind; return VRL error on Err

Test plan

  • New regression tests added for every fixed panic path (exploit inputs that fail without the fix, pass with it)
  • cargo test --lib: 1680 passed, 0 failed (was 1671 before new tests)
  • No existing tests broken

🤖 Generated with Claude Code

….10743 batch J)

Close all panics and DoS-by-OOM paths identified in the batch-J security audit:

- OBE-10722 find(): clamp negative `from` to 0 before usize cast; guard
  find_regex_in_str against offset > haystack.len() (regex::find_at panic).
- OBE-10723 format_number(): replace .expect("not NaN") with fallible
  Decimal::from_f64 conversion; returns VRL error for ±∞ and out-of-range floats.
- OBE-10724 format_number(): reject negative scale; cap scale at 1024 to prevent
  unbounded push('0') OOM loop; type_def changed to fallible().
- OBE-10727 arithmetic: add safe_mul/safe_add/safe_rem helpers mirroring safe_sub;
  replace NotNan::mul/add/rem calls that panic on NaN result (e.g. ∞ * 0).
- OBE-10731 parse_xml(): filter single-child path to element/text nodes; prevents
  Comment/PI child from reaching the unreachable!() arm in process_node.
- OBE-10733 starts_with(): fix hand-rolled Chars iterator — treat width==0 (stray
  continuation bytes) and truncated multi-byte sequences as error bytes; fix
  off-by-one in the Err arm that read past the advanced pos.
- OBE-10734 lex.rs: add b'}' => '}' arm to unescape_string_literal; the lexer
  already accepted \} via escape_code but the unescaper had no matching arm,
  hitting unimplemented!().
- OBE-10735 array insert: cap insert_value index at ±32768 to bound Null-padding
  loop; cap Vec::with_capacity in crud/insert.rs to the same limit.
- OBE-10743 parse_grok(): wrap pattern.match_against in catch_unwind to convert
  Oniguruma retry-limit panics to VRL errors (mirrors existing parse_groks guard).

All 1680 lib tests pass. New regression tests added for each fixed panic path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant