GHSA-55rh-j682-vgvp: 
Python Analyse et atténuation de la vulnérabilité

Summary

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.

Affected versions

  • Go module 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.
  • PyPI package trail-evidence: 0.2.0 and 0.2.1.
  • GitHub Action RainerGewalt/trail-evidence: @v0.1.0 to @v0.2.1, and any reference to a commit of main before the fix.
  • Browser verifier at https://rainergewalt.github.io/trail-evidence/ until the patched version is deployed.

Patched versions

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.

Severity

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).

Description

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:

  • Duplicate member names. The parsers silently kept one of two members with the same name. A record line could therefore carry an extra member with the same name as a hashed member, at the top level or inside the payload, and still verify, while a reader that keeps the first value sees a different record. The Go verifier rejected some of these cases, the Python and browser verifiers accepted them, so the verdicts also differed between verifiers.
  • Data after the object. The Go verifier accepted a line with arbitrary non-JSON data after the record object. The Python verifier split lines at a lone carriage return, so two records on one line were read as two lines.
  • Bytes that are not UTF-8. The browser verifier decoded files with replacement characters, so a line with invalid bytes in a string could verify against hashes computed over the replacement character. The Python verifier ended with an exception instead of a report.
  • Unpaired surrogates, nesting depth, white space. Handled differently by each verifier; the Python verifier ended with an exception on deep nesting.
  • No input. An empty journal had the verdict 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.

Workarounds

Until the patched version is installed:

  • In CI, check before verifying that each journal path is a regular, non-empty file, and fail the job otherwise, for example test -f "$f" && test -s "$f". With the Action, also fail when the output records is 0.
  • Reject journals with malformed lines before verifying them. A strict check with the Python standard library: 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.
  • Prefer the Go or Python CLI over the browser page for files of unknown origin until the page is updated.
  • Programs that read verified journals should use a JSON parser that rejects duplicate member names, and should not rely on members that are not hashed (job_id, correlation_id, decision_id, context, redaction, anchor, signature).

References


Source: NVD

Connexe Python Vulnérabilités :

CVE ID

Gravité

Partition

Technologies

Nom du composant

Exploit CISA KEV

A corrigé

Date de publication

GHSA-98qm-p6jx-5wj2HIGH7.5
  • Python logoPython
  • soupsieve
NonOuiNov 14, 2026
GHSA-wrrw-x2x3-vvp7MEDIUM6.1
  • Python logoPython
  • mailvigil
NonOuiNov 14, 2026
GHSA-55rh-j682-vgvpMEDIUM5.5
  • Python logoPython
  • github.com/rainergewalt/trail-evidence/go
NonOuiNov 14, 2026
GHSA-cg3f-7pqx-v33vMEDIUM4.8
  • Python logoPython
  • authlib
NonOuiNov 14, 2026
GHSA-q45f-7qmf-37x3MEDIUMN/A
  • Python logoPython
  • pysacd
NonOuiNov 14, 2026

Évaluation gratuite des vulnérabilités

Évaluez votre posture de sécurité cloud

É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.

Évaluation de la demande

Ressources Wiz supplémentaires

Obtenez une démo personnalisée

Prêt(e) à voir Wiz en action ?

"La meilleure expérience utilisateur que j’ai jamais vue, offre une visibilité totale sur les workloads cloud."
David EstlickRSSI
"Wiz fournit une interface unique pour voir ce qui se passe dans nos environnements cloud."
Adam FletcherChef du service de sécurité
"Nous savons que si Wiz identifie quelque chose comme critique, c’est qu’il l’est réellement."
Greg PoniatowskiResponsable de la gestion des menaces et des vulnérabilités