Skip to content

Platform-dependent delegation path matching

Moderate
jku published GHSA-qp9x-wp8f-qgjj May 18, 2026

Package

pip tuf (pip)

Affected versions

<= 6.0.0

Patched versions

7.0.0

Description

DelegatedRole._is_target_in_pathpattern uses fnmatch.fnmatch to decide
whether a given target path is authorized by a delegation's glob pattern.
Python's fnmatch.fnmatch calls os.path.normcase() on both arguments
before matching. On POSIX hosts normcase is the identity function; on
Windows hosts os.path resolves to ntpath, whose normcase lowercases
its input and replaces / with \.

As a result, python-tuf's delegation path pattern matching is
case-sensitive on Linux/macOS but case-INSENSITIVE on Windows. This makes the
authorization decision for a target dependent on the host operating system
of the client running the updater.

The result on Windows is a TUF specification violation in the python-tuf ngclient implementation.

Vulnerable code

tuf/api/_payload.py (HEAD 7ecb67d):

1183  @staticmethod
1184  def _is_target_in_pathpattern(targetpath: str, pathpattern: str) -> bool:
1185      """Determine whether ``targetpath`` matches the ``pathpattern``."""
1186      # We need to make sure that targetpath and pathpattern are pointing to
1187      # the same directory as fnmatch doesn't threat "/" as a special symbol.
1188      target_parts = targetpath.split("/")
1189      pattern_parts = pathpattern.split("/")
1190      if len(target_parts) != len(pattern_parts):
1191          return False
1192
1193      # Every part in the pathpattern could include a glob pattern, that's why
1194      # each of the target and pathpattern parts should match.
1195      for target, pattern in zip(target_parts, pattern_parts, strict=True):
1196          if not fnmatch.fnmatch(target, pattern):
1197              return False
1198      return True

fnmatch.fnmatch source (Python 3.12, unchanged in current mainline):

def fnmatch(name, pat):
    ...
    name = os.path.normcase(name)
    pat = os.path.normcase(pat)
    return fnmatchcase(name, pat)

Fix

Replace fnmatch.fnmatch with fnmatch.fnmatchcase, which is explicitly documented as "not applying
case normalization", so it behaves identically across platforms.

Attack

  1. A TUF repository with two path-based delegations whose patterns differ only in case — for example,
    Foo/* and foo/*.
  2. The "attacker" delegation is listed BEFORE the "legit" delegation in the delegation order
  3. The client searches for foo/something: on Windows, it will find the "attacker" provided target "Foo/something".

Exploitability caveats

  • The attack needs a repository configuration with case-colliding delegation path patterns. The attacker must control one of the delegated roles
  • Delegation ordering matters: the attacker-controlled role must be visited BEFORE the legit role in the pre-order walk
  • The client must run on Windows. No effect on Linux/macOS.

Credit

Reporter: Koda Reef @kodareef5
Advisory edits: Jussi Kukkonen @jku

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
None
Integrity
Low
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

CVE ID

No known CVE

Weaknesses

Improper Handling of Case Sensitivity

The product does not properly account for differences in case sensitivity when accessing or determining the properties of a resource, leading to inconsistent results. Learn more on MITRE.

Credits