Skip to content

bug: ResolvedWorkloadIdentity deserialization skips the non-root and ordering invariants of new() #5189

Closed

Description

@EmilienM

User Story

I run OpenShell sandboxes with the Podman and Kubernetes drivers, and I read through the isolation core (openshell-sandbox, openshell-binary-identity, openshell-isolation-interface) at 00528d24a. This item comes from reading the code. I have not hit it in production. It is one line of the umbrella issue #5179.

Problem Statement

ResolvedWorkloadIdentity (crates/openshell-isolation-interface/src/contract.rs:144) has public fields and derives Deserialize. ResolvedWorkloadIdentity::new enforces a non-root identity, non-empty source and resource_digest, and sorted, de-duplicated supplementary groups, but a value decoded with serde bypasses all of that. For example, the supervisor decodes SandboxRuntimeDescriptor with serde_json (backend_setup.rs), and the descriptor embeds the identity.

Impact / Why This Matters

A descriptor with uid: 0, an empty source, or unsorted duplicate groups is accepted and used as the launch identity and in boundary confirmation, despite the type's "exact non-root identity" contract. The descriptor comes from a trusted peer today, so this is contract hardening.

Acceptance Criteria

  • Decoding goes through new() (for example #[serde(try_from = "RawResolvedWorkloadIdentity")]), so invalid values fail to deserialize.
  • Tests cover uid 0, empty fields, and unsorted or duplicate groups.
  • The other contract types whose validate() checks only part of what they carry are listed in the PR as follow-ups.

Reproduction Steps

Found by reading the code; not reproduced live. Deserialize {"uid":0,"gid":0,"supplementary_gids":[3,1,1],"source":"","resource_digest":""} into ResolvedWorkloadIdentity in a unit test and observe it succeeds.

Environment

  • OpenShell: main at 00528d24a
  • OS: Fedora 44, Linux 7.2.14
  • Deployment: Podman driver (local gateway); code read for the Kubernetes driver too

Activity

  1. added
    state:acceptedA maintainer decided OpenShell should pursue this issue
    and removed
    state:triage-neededOpened without agent diagnostics and needs triage
    on Nov 3, 2026
  2. mrunalp commented on Nov 3, 2026

    @mrunalp
    Collaborator

    Accepted for implementation in #5192.

    Source inspection at 32dcc4a67: ResolvedWorkloadIdentity derives Deserialize directly, while its non-root, required-field, and group-normalization checks live in new(). Routing deserialization through that constructor addresses the contract gap. This is hardening of a descriptor supplied by a trusted peer.

    This assessment is based on the source and the linked report/PR; I have not independently run deployment reproductions or the PR test suite. CI and code review still need to validate the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    state:acceptedA maintainer decided OpenShell should pursue this issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions