Skip to content

LeaseConstraints.expiresAt is not validated to be UTC (Z-suffixed) (§9.5) #100

@nficano

Description

@nficano

Category: spec-conformance Severity: minor
Location: Sources/ARCP/Runtime/JobManager.swift:162-183, Sources/ARCP/Messages/Execution.swift:8-19
Spec: ARCP v1.1 §9.5 ("expires_at is ISO 8601 with timezone, MUST be UTC (Z suffix) ... Past or invalid values are rejected with INVALID_REQUEST.")

What

LeaseConstraints.expiresAt decodes through the envelope's custom Date strategy, which accepts any RFC3339 offset (e.g. +02:00) via ISO8601DateFormatter. §9.5 requires the value be UTC with a Z suffix and that non-UTC/invalid values be rejected with INVALID_REQUEST. The runtime only checks expiresAt <= Date() (past), not the timezone form. A client sending 2026-05-13T23:42:00+02:00 is silently accepted and converted, rather than rejected. Because Date discards the original zone, this must be enforced at the string-decoding boundary.

Evidence

if let constraints = payload.leaseConstraints, constraints.expiresAt <= Date() {
    // only the "past" check; no UTC/Z-suffix validation

LeaseConstraints uses the default Date codable (envelope custom strategy parses any offset).

Proposed fix

Give LeaseConstraints a custom decoder that decodes expires_at as a String, requires a Z suffix (or +00:00), and throws INVALID_REQUEST otherwise before converting to Date.

Acceptance criteria

  • A non-Z expires_at is rejected with INVALID_REQUEST.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions