Skip to content
Fencer Vulns
no cvss —

OSEC-2026-21 json

Str partial-match stale capture registers underflow

published 2026-10-23 16 d ago modified 2026-11-06 2 d ago

cvss
—
not scored
cisa kev
Not listed
not in CISA's catalog
epss
—
no score, EPSS covers CVEs only
public exploits
0
none known

Summary

ANT-2026-KKC4QS4S Str partial-match stale capture registers underflow

`Str.string_partial_match` records the beginning and end of a captured group. There was an implicit assumption that `beginning <= end`. However if it reached the end of the matched string but not the end of the regexp, it was possible for the beginning of the group to be matched at iteration N of the star operator, and the end of the group to be matched at iteration N-1, resulting in `beginning > end`. `Str.matched_group` is safe, it fails with an `Invalid_argument` on groups with `beginning > end`, but `Str.replace_matched` can crash, trying to memcpy `end - beginning` bytes.

The example in the ANT is `ab` partially matched against `\(\(a\)b\)+`. Group 2 has `beginning = 2` and `end = 1`.

## Fix

The fix is to record groups with `beginning > end` as not matched.

## Am I affected?

All of the following conditions are necessary: * you need to use `Str.string_partial_match` * if you don't use this function you are not affected * you need to use one of `Str.{replace_matched,global_replace,replace_first}` on the same regexp after a call to `Str.string_partial_match`. * If you use `Str.group_beginning` and `Str.group_end` and do your own string manipulation that is safe, because the String module would raise on out of bounds accesses. Similarly `Str.matched_group` is safe (uses `String` functions in its OCaml implementation) * the match replacement must reference a group > 0 * if the replacement string argument is fixed, and doesn't reference any groups, or references only group 0, then you are not affected * the referenced replacement group must be under a repetition operator in the original regexp * if there is no repetition operator in the regexp, or there are no groups under the repetition operator then you are not affected

For example `{|\(\(a\)b\)+|}` as the regular expression in a call to `Str.string_partial_match`, followed by a reference to `\2` in the argument of `Str.replace_matched` could be affected.

## Timeline

- 2026-08-24: vulnerability was found - 2026-08-27: forwarded report to security@ocaml.org - 2026-09-29: fix merged to trunk

Patch / fix

  • opam ocaml 4.14.5, 5.5.2

Affected packages

ecosystem package affected fixed in
opam ocaml
<4.14.5
>=5, <5.5.2
4.14.5
5.5.2

Sources

Fencer Vulns keeps one entry per vulnerability: the CVE id wins, then GHSA, and records that alias each other are merged, except that two CVEs always keep separate entries. The same data is available as JSON.