
PEACH
Un cadre d’isolation des locataires
The Go, Python and browser verifiers of trail-evidence, and the GitHub
Action that runs the Go verifier, could report a journal as valid
although it contained record lines that are not well-formed JSON objects
in the sense the format relies on, or although nothing was verified at
all. Depending on the verifier, a record line with duplicate member names,
data after the JSON object, bytes that are not UTF-8, or an unpaired
surrogate escape could pass, while another verifier rejected the same
file. A directory passed to the Go verifier or the Action was reported as a
valid journal, and an empty journal was valid with exit code 0 in all
verifiers.
github.com/RainerGewalt/trail-evidence/go and the
trail-evidence CLI: v0.1.0, v0.2.0, v0.2.1 (all releases up to and
including 0.2.1), including the release archives.trail-evidence: 0.2.0 and 0.2.1.RainerGewalt/trail-evidence: @v0.1.0 to @v0.2.1, and
any reference to a commit of main before the fix.0.2.2 for the Go module, the CLI release
archives, the PyPI package and the Action tag; the browser verifier has served the fix since it reached main
on 12 November 2026.
Moderate, CVSS v3.1 5.5
(CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N).
Reasoning: The impact is on integrity, the very property the tool exists
to check: a verdict of valid can be wrong. An attacker needs to be able
to modify or supply the journal file, which is the threat model a
tamper-evident journal is meant to address, and a user or pipeline has to
verify that file (user interaction). For duplicate member names, the
modified content is only misread by programs whose JSON parser keeps the
first of two members with the same name; the verifiers themselves and most
common parsers keep the last, which is why the hashes still matched.
Signatures do not detect this case, because the hashed content is
unchanged. The empty-journal and unreadable-input cases need no attacker,
only a producer that writes nothing or a path that is not a journal, and
make a CI check pass that should fail. No confidentiality or availability
impact. The rating could be argued lower (Low integrity impact) because
exploitation of the duplicate-name case depends on a downstream reader;
it is kept at High because a passing verification is a statement about
integrity that users rely on.
Weaknesses: CWE-436 (Interpretation Conflict), CWE-636 (Not Failing
Securely, "Failing Open"), CWE-20 (Improper Input Validation).
A Trail Evidence journal is a JSON Lines file; every record is hashed in its RFC 8785 canonical form, and the records are chained. RFC 8785 assumes I-JSON input (RFC 7493), but the specification did not say how a verifier must treat a line that is not I-JSON, and the three verifiers relied on their language's JSON parser:
valid (exit code 0) in
all verifiers. The Go verifier, and therefore the Action, treated a read
error, for example a directory matched by a glob, as the end of an empty
journal and reported valid with exit code 0.
The fix adds explicit reading rules to the specification (a record line is
one JSON object: valid UTF-8, unique member names at every depth, no
unpaired surrogate, at most 64 levels of nesting, nothing else on the line;
a line that breaks a rule is schema_invalid), makes a journal without
records incomplete (exit code 3, not accepted by --allow-incomplete),
and gives a journal that cannot be read no verdict and exit code 2. All
three verifiers implement the same rules, and the conformance suite has a
fixture for each rule that every verifier must pass. Record hashes do not
change; journals whose lines keep the rules verify as before.
In addition, the command line and Action summaries now state when
signatures were not checked, so that a summary such as "4 signed record(s)"
is no longer read as a passed signature check.Until the patched version is installed:
test -f "$f" && test -s "$f". With the Action, also fail when the
output records is 0.python import json, sys def strict(pairs): names = [k for k, _ in pairs] if len(names) != len(set(names)): raise ValueError("duplicate member name") return dict(pairs) bad = 0 with open(sys.argv[1], "rb") as fh: for n, raw in enumerate(fh, 1): line = raw.strip(b" \t\r\n") if not line: continue try: value = json.loads(line.decode("utf-8"), object_pairs_hook=strict) # fails on an unpaired surrogate in any string or name json.dumps(value, ensure_ascii=False).encode("utf-8") except (ValueError, RecursionError) as exc: print(f"line {n}: {exc}") bad += 1 sys.exit(1 if bad else 0)
It does not enforce the nesting limit of 64 levels; use it in addition to
the verifier, not instead of it.job_id, correlation_id, decision_id, context,
redaction, anchor, signature).SPEC.md sections 2, 6.3, 6.4, 6.6 and 10 in 0.2.2.Source: NVD
Évaluation gratuite des vulnérabilités
Évaluez vos pratiques de sécurité cloud dans 9 domaines de sécurité afin d’évaluer votre niveau de risque et d’identifier les lacunes dans vos défenses.
Obtenez une démo personnalisée
"La meilleure expérience utilisateur que j’ai jamais vue, offre une visibilité totale sur les workloads cloud."
"Wiz fournit une interface unique pour voir ce qui se passe dans nos environnements cloud."
"Nous savons que si Wiz identifie quelque chose comme critique, c’est qu’il l’est réellement."