TROVE-2026-024: Malicious directory cache can crash arti clients
### Meta
Reported by 5225225, see arti!4049.
Assigned TROVE-2026-024 for it.
Keeping this confidential for now but I think we can open it up, given that it is a zero day.
### Synopsis
a44d2e1c600b710b7a669dce96b37108302318a0 introduced changes to an already not-so-nice parser for `PortPolicy`.
The code can be found below:
```rust
/// Very bad parser for [`PortPolicy`], please use `parse2`!
fn from_str(s: &str) -> Result<Self, Self::Err> {
// TODO: The error is bad but kept for backwards compatibility.
// Also, we should do split_whitespace but I feel doing this is not
// worth it anymore; introduces an unnecessary risk of adding
// bugs.
if s.len() < 7 {
// We need to do this because RuleKind::from_str does not check for
// the space between "accept/reject" and the arguments.
return Err(PolicyError::InvalidPort);
}
let kind = RuleKind::from_str(&s[..6]).map_err(|_| PolicyError::InvalidPort)?;
let s = &s[7..];
let mut allowed = PortRanges::from_str(s)?;
if kind == RuleKind::Reject {
allowed.invert();
}
Ok(Self { allowed })
}
```
The problem here are the following lines:
```
let kind = RuleKind::from_str(&s[..6]).map_err(|_| PolicyError::InvalidPort)?;
let s = &s[7..];
```
This will crash in the case if it rips up a UTF-8 code point, as per [`SliceIndex<str>`](https://doc.rust-lang.org/std/primitive.str.html#impl-SliceIndex%3Cstr%3E-for-(Bound%3Cusize%3E,+Bound%3Cusize%3E))
> Panics if begin or end (if it exists and once adjusted for inclusion/exclusion) does not point to the starting byte offset of a character (as defined by is_char_boundary), if begin > end, or if end > len.
A potential example of this is the following input: `acce ¬`, as it contains a two byte UTF-8 point at `5..=6`, which gets cut off by `&s[0..6]`.
### Solutions
Use `.split()` or something similar to safely split the string.
### Impact
Unfortunately, `tor-dirmgr` only verifies the digest provided by a secure and trusted dirauth **after** parsing it, meaning that a malicious directory mirror can provide an invalid microdesc that will lead arti to crash before noticing the checksum violation.
I think we should backport this.
I assigned `TROVE-2026-024` and severity `Medium` for it because it can denial someones service but no privacy leaks are involved, making `High` unjustified.
cc @nickm @Diziet
issue