PT-2026-41481 · Crates.Io · Kanidmd Lib

Published

2026-05-06

·

Updated

2026-05-06

CVSS v4.0

6.9

Medium

VectorAV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:L

Summary

The POST /v1/domain/ image and POST /v1/oauth2/{rs name}/ image handlers call validate image() on the uploaded body before the ACL check that restricts image upload to admins. Any bug in an image validator is therefore reachable by an unauthenticated remote client rather than being admin-gated.
One such bug exists today: png has trailer() panics on inputs shorter than 8 bytes, or whose first chunk-length field is near u32::MAX.
On a default build this has no server-wide impact. The panic unwinds only the requester's own tokio task; the server process survives, no shared state is poisoned, and other connections are unaffected. This was reported privately rather than as a public issue because (a) the project previously treated an admin-triggered thread crash of identical impact as security-relevant (e51d0dee4), and this is reachable by a broader population; and (b) a downstream build with panic = "abort" would upgrade it to an unauthenticated process-crash DoS.

Details

Validate-before-authorize ordering

Both handlers parse and validate attacker-controlled bytes before checking whether the caller is permitted to upload at all:
  • server/core/src/https/v1 domain.rs:118image.validate image() runs; handle image update(client auth info, …) (the ACL check) is at line 129.
  • server/core/src/https/v1 oauth2.rs:550 — same ordering.
The VerifiedClientInformation extractor (server/core/src/https/extractors/mod.rs:18-90) always returns Ok — it builds a ClientAuthInfo from whatever credentials are present (including none) and does not reject anonymous callers. Authorization is deferred to handle image update(), which is never reached if the validator panics or errors first.

PNG validator panic (demonstrator)

validate image() (server/lib/src/valueset/image/mod.rs:98) checks only a 256 KiB maximum size, not a minimum, before dispatching to the format-specific validator.
Short inputserver/lib/src/valueset/image/png.rs:73-76:
rust
pub fn png has trailer(contents: &Vec<u8>) -> Result<bool, ImageValidationError> {
  let buf = contents.as slice();
  let (magic, buf) = buf.split at(PNG PRELUDE.len()); // 8; panics if len < 8
Chunk-length overflowserver/lib/src/valueset/image/png.rs:46,53:
rust
if buf.len() < (length + 4) as usize {  // length: u32; wraps before the usize cast
  ...
}
let ( , buf) = buf.split at(length as usize);  // panics for length ≈ u32::MAX
In a release build 0xFFFF FFFC + 4 wraps to 0, the guard passes, and split at panics.

PoC

sh
printf 'x89PNG' > /tmp/short.png
curl -sk https://$KANIDM HOST/v1/domain/ image 
   -F 'image=@/tmp/short.png;type=image/png;filename=x.png'
# → connection reset / empty reply; server process remains up
Unit-test confirmation (cargo test -p kanidmd lib --lib):
rust
#[test]
fn audit png short input panics() {
  let short = vec![0x89u8, 0x50, 0x4e, 0x47];
  assert!(std::panic::catch unwind(|| png has trailer(&short)).is err());
}

#[test]
fn audit png chunk length overflow panics() {
  let mut data = vec![0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
  data.extend from slice(&[0xFF, 0xFF, 0xFF, 0xFD]);
  data.extend from slice(b"IHDR");
  data.extend from slice(&[0u8; 8]);
  assert!(std::panic::catch unwind(|| png has trailer(&data)).is err());
}
Both tests pass (i.e. both inputs panic).

Impact

The only party affected is the requester, whose own connection is dropped. Repeating the request has no cumulative effect beyond ordinary request load.
On the upstream build:
  • Each connection runs in its own tokio::task::spawn (server/core/src/https/mod.rs:481); the accept loop continues after a task panic.
  • No panic = "abort" in any workspace [profile.*].
  • No Mutex/RwLock held across the call site; nothing is poisoned.
  • The panic occurs before any write actor is messaged; no DB or replication state is touched.
Residual risk: a downstream packager that sets panic = "abort" (or links code that installs an abort handler) would see a full unauthenticated process crash. (No such packager is known)
Affected: v1.1.0-rc.15 (introduced in e7f594a1c, #2112) through master @ edf50b9da.

Fix

Integer Overflow

RCE

Found an issue in the description? Have something to add? Feel free to write us 👾

Weakness Enumeration

Related Identifiers

GHSA-84JC-3HJ2-HWC7

Affected Products

Kanidmd Lib