fix(security): prevent 9 panic/OOM vectors in VRL runtime (batch J) - #7
Open
JuanMantica45 wants to merge 3 commits into
Open
fix(security): prevent 9 panic/OOM vectors in VRL runtime (batch J)#7JuanMantica45 wants to merge 3 commits into
JuanMantica45 wants to merge 3 commits into
Conversation
….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>
Batch J fixed 9 panic/OOM paths but only 4 of them shipped a regression test.
Add tests for the remaining 5 and prove each one actually protects its guard.
Unit tests (11 new):
- OBE-10727 arithmetic.rs: new tests module covering safe_mul/safe_add/safe_rem —
inf*0, inf+-inf and inf%inf return errors, and overflow to inf stays valid.
- OBE-10731 parse_xml: comment-only child, PI-only child, and a comment beside an
element child.
- OBE-10734 lex.rs: unescape_string_literal handles `\}` (and `\{\}`).
- OBE-10735 crud/insert.rs: indices beyond ±32768 are rejected and leave the array
untouched; index 32768 still works.
VRL source-level tests (4 new, lib/tests/tests/issues/): the same four defects
driven through compile+run, which is the path operator-authored VRL actually takes.
Each was confirmed to panic (or, for OBE-10735, to allocate an unbounded array)
against a pre-fix build of the CLI.
OBE-10743 is deliberately left untested: grok 2.4.1's onig backend already converts
Oniguruma errors to `None` via `unwrap_or_default()` (see grok src/onig.rs:53), so
the retry-limit panic the catch_unwind guards is not reachable with the pinned
dependency. No exploit input could be constructed.
Also fixes gates the original commit broke, none of which `cargo test --lib` runs:
- format_number's documented example no longer compiled after type_def became
fallible, failing the generated `functions/format_number` test — now uses
`format_number!`.
- `cargo fmt --check` flagged three hunks in arithmetic.rs and xml.rs.
- `clippy::all` (denied in src/value/mod.rs) flagged the MAX_ARRAY_INDEX check as
manual_range_contains.
- Added the changelog fragments CI requires, including a `breaking` entry for
format_number becoming fallible.
cargo test --workspace: 1692 passed, 0 failed.
vrl-tests: 765 passed, 0 failed (761 before).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mahendra-s1
approved these changes
Aug 10, 2026
Removes changelog.d/7.security.md and changelog.d/7.breaking.md. Note: scripts/check_changelog_fragments.sh requires at least one fragment per PR, so PR Sentinel-One#7 now needs the 'no-changelog' GitHub label to pass that CI check. The breaking change the fragment documented still stands: format_number is now fallible, so programs calling it without `!` or `??` will no longer compile. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| @@ -0,0 +1,12 @@ | |||
| # issue: OBE-10735 | |||
There was a problem hiding this comment.
I think we should leave this change out - there could be a valid use case for indexing beyond 32769.
ajayshekar-s1
requested changes
Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
stdlib/find.rsfromwraps tousize::MAX→regex::find_atpanics whenoffset > haystack.len()from.max(0)before cast; add bounds check infind_regex_in_strstdlib/format_number.rsDecimal::from_f64(*v).expect("not NaN")panics on ±∞ and floats > 7.9e28 (NotNanpermits ∞).ok_or_else(...)?returning a VRL errorstdlib/format_number.rsscale: i64 as usize+ unboundedpush('0')loop → OOM for large/negative scaletype_deftofallible()compiler/value/arithmetic.rsNotNan::mul/add/rempanic when result is NaN (e.g.∞ * 0,∞ + -∞,∞ % ∞);try_subwas already fixed (#1186) but mul/add/rem were notsafe_mul,safe_add,safe_remmirroring the existingsafe_subpatternparsing/xml.rsnode.children().next()without filtering; a Comment/PI child reachesprocess_node→_ => unreachable!()stdlib/starts_with.rsChars::nextusesutf8_width::get_widthreturning 0 for stray bytes → slice of length 0 →from_utf8("") = Ok→"".chars().next() = None→.unwrap()panicswidth == 0and truncated sequences as error bytes; fix off-by-one inErrarmparser/lex.rsescape_codeaccepts\}butunescape_string_literalhas nob'}'arm → hitsunimplemented!()b'}' => '}'armvalue/value/crud/mod.rs+insert.rsinsert_valuepads withValue::Nullup to arbitrary index with no cap → OOM;Vec::with_capacity(index+1)also uncappedwith_capacityto the same limitstdlib/parse_grok.rspattern.match_againstuses externalgrokcrate whose Oniguruma regex engine panics on retry-limit exhaustion;parse_grokshascatch_unwindbutparse_grok(singular) does notmatch_againstinstd::panic::catch_unwind; return VRL error onErrTest plan
cargo test --lib: 1680 passed, 0 failed (was 1671 before new tests)🤖 Generated with Claude Code