Cyphrme / Cyphrme/Cyphr

Identifier decoder canonicality is relied on but never tested

Open
#150 1 comment 0 reactions 0 assignees View on GitHub
security tech-debt
Dominant language
Rust
Stars
3
Forks
0
Avg merge
1d 42m
Merged PRs (30d)
11

Description

Witness reports parse their principal identifier through a strict unpadded url-safe base64 decoder, and the source states that strictness is load-bearing: if two distinct spellings of the same value could both be accepted, they would compare unequal and reopen the evasion the typed parse exists to close.

**No test exercises that.** The malformed-string generator produces alphanumeric strings of bounded length, so every case it rejects is rejected on *length*. Nothing feeds the parse a padded encoding, a standard-alphabet encoding using characters outside the url-safe set, or a value with non-zero trailing bits — the three ways a decoder can be lenient about form while accepting the same underlying bytes.

## Why it matters

The property being relied on is a bijection: exactly one accepted string per value. That was verified empirically once, outside the repository, by brute-forcing substitutions against the pinned decoder and confirming only one round-trips. But that verification lives in a review, not in the suite.

So the guarantee currently rests on a dependency's behaviour with nothing in the tree pinning it. Swap the decoder for a lenient one, or take an upgrade that relaxes its input handling, and equivocation detection reopens with a fully green suite. Nothing would fail.

This is the same shape as a defect corrected in the same work: a comment asserting a security property that no evaluator checks. It was accepted knowingly at the merge gate rather than missed, and is recorded here so the acceptance is visible rather than implicit.

## What resolving this involves

Cases that fail on *form* rather than length: a valid digest with padding appended, the same bytes written in the standard alphabet, and a value whose final character carries non-zero trailing bits. Each must be rejected, and rejected loudly rather than read as a different value.

Worth doing as a property over encoding variants rather than three examples, since the interesting space is "strings that decode to the same bytes" and that space is enumerable for a fixed digest.

The tagged-digest fields share the same decoder and the same absence of coverage.

Related: #141, #148.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by locating the strict unpadded URL-safe decoder used for witness report principal identifiers and the malformed-string generator that currently varies only length. Add property coverage for padded encodings, standard-alphabet variants, and non-zero trailing bits, including the shared tagged-digest fields. Done means every encoding variant that represents the same bytes is rejected, with failures reported by the suite.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
security, testing
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.