dfetch Supply Chain¶
Risk Context¶
This report follows the risk-based approach of BSI TR-03183-1 Chapter 5.
Threat model for dfetch. Covers the pre-install lifecycle: code contribution, CI/CD, build (wheel / sdist), PyPI distribution, and consumer installation. The installed dfetch package is the handoff point to tm_usage.py.
Assumptions¶
Name |
Description |
|---|---|
Trusted workstation |
Developer workstations are trusted at development and commit time. A compromised workstation is outside the scope of this model. |
CI runner posture |
GitHub Actions environments inherit the security posture of the GitHub-hosted runner. Ephemeral runner isolation is provided by GitHub. |
Actors¶
Name |
Description |
|---|---|
Developer / Contributor |
Anyone who writes code for dfetch: core maintainers who push directly and cut releases, and external contributors who submit pull requests. Maintainers are trusted at workstation time and are responsible for correct branch-protection and release workflow configuration. External contributors are untrusted until their PR passes code review and CI. |
Consumer / End User |
Installs dfetch from PyPI ( |
Boundaries¶
Name |
Description |
|---|---|
Local Developer Environment |
Developer workstation or local CI runner. Assumed trusted at invocation time. Hosts the manifest ( |
Consumer Environment |
End-user workstation or downstream CI pipeline where dfetch is installed and invoked. Distinct from the developer environment: no source checkout, no signing keys, no deploy access. The consumer is trusted at invocation time but has no special relationship with the dfetch release infrastructure. |
GitHub Platform |
GitHub-hosted infrastructure: repository, CI/CD runners, Actions workflows, build cache, and code-scanning results. Egress traffic on runners is blocked ( |
PyPI / TestPyPI |
Python Package Index and its staging registry. dfetch publishes via OIDC trusted publishing - no long-lived API token stored. |
Data Flow Diagram¶
Sequence Diagram¶
Asset Identification¶
Name |
Description |
Type |
C / I / A |
|---|---|---|---|
A-01: GitHub Repository (main / protected) |
The protected |
ExternalEntity |
High / High / High |
A-01b: GitHub Repository (feature branches / PRs) |
Unprotected feature branches and fork PRs: no mandatory review, no CI-gate requirement to push. Any authenticated GitHub user can open a PR modifying |
ExternalEntity |
— / — / — |
A-02: GitHub Actions Infrastructure |
Microsoft-operated ephemeral runner executing CI/CD workflows. Egress policy is |
ExternalEntity |
High / High / High |
A-03: PyPI / TestPyPI |
Python Package Index - both the registry service and the published dfetch wheel/sdist (https://pypi.org/project/dfetch/). Published via OIDC trusted publishing; no long-lived API token stored. A machine-readable CycloneDX SBOM is generated during the build and published alongside the release. Account takeover, registry compromise, or namespace-squatting would affect every consumer installing dfetch. |
ExternalEntity |
High / High / High |
A-04: Release Gate / Code Review |
Branch-protection rules and mandatory peer code review enforced before merging to the default branch. Controls privileged operations: PR merge, direct push to main, and release-workflow trigger. A compromised maintainer account with merge rights bypasses peer review and can trigger a malicious release without any automated block. No hardware-token MFA or mandatory second-maintainer approval for release operations is currently enforced. |
Process |
High / High / High |
A-05: PyPI OIDC Identity |
GitHub OIDC token exchanged for a short-lived PyPI publish credential. No long-lived API token stored. The token is scoped to the GitHub Actions environment named |
Data |
High / High / High |
A-06: GitHub Actions Workflow |
CI/CD pipelines: test, build (wheel/msi/deb/rpm), lint, CodeQL, Scorecard, dependency-review, docs, release. All actions pinned by commit SHA. harden-runner used in every workflow that executes steps on a runner (egress: block with endpoint allowlist); ci.yml is a dispatcher-only workflow with no runner steps and does not include harden-runner. |
Process |
Medium / Medium / Medium |
A-07: dfetch Build / Dev Dependencies |
Python packages installed during CI: setuptools, build, pylint, bandit, mypy, pytest, etc. Ruby gem |
Datastore |
High / High / — |
A-08: Python Build (wheel / sdist) |
Runs |
Process |
High / High / High |
A-08b: GitHub Actions Build Cache |
GitHub Actions cache entries written and restored across pipeline runs. Used to speed up dependency installation (pip, gem) and incremental builds. Cache-poisoning from forked PRs (DFT-28, SLSA E6: poison the build cache) is mitigated by ref-scoped cache keys: build.yml includes |
Datastore |
High / High / — |
Dataflows¶
Name |
From |
To |
Protocol |
|---|---|---|---|
DF-11: Push commits / open PR |
Developer / Contributor |
A-01b: GitHub Repository (feature branches / PRs) |
HTTPS |
DF-22: PR enters code review |
A-01b: GitHub Repository (feature branches / PRs) |
A-04: Release Gate / Code Review |
|
DF-12: Main branch workflows drive CI execution |
A-01: GitHub Repository (main / protected) |
A-06: GitHub Actions Workflow |
|
DF-13a: PR CI checkout |
A-01b: GitHub Repository (feature branches / PRs) |
A-02: GitHub Actions Infrastructure |
|
DF-13b: Release CI checkout |
A-01: GitHub Repository (main / protected) |
A-02: GitHub Actions Infrastructure |
|
DF-14: CI cache restore |
A-08b: GitHub Actions Build Cache |
A-02: GitHub Actions Infrastructure |
HTTPS |
DF-15: Workflow triggers build step |
A-06: GitHub Actions Workflow |
A-08: Python Build (wheel / sdist) |
|
DF-15b: Built wheel/sdist artifacts |
A-08: Python Build (wheel / sdist) |
A-02: GitHub Actions Infrastructure |
|
DF-16: CI fetches build/dev deps from PyPI |
A-03: PyPI / TestPyPI |
A-07: dfetch Build / Dev Dependencies |
HTTPS |
DF-17: Build tools consumed by build step |
A-07: dfetch Build / Dev Dependencies |
A-08: Python Build (wheel / sdist) |
|
DF-18: CI cache write |
A-02: GitHub Actions Infrastructure |
A-08b: GitHub Actions Build Cache |
HTTPS |
DF-19: CI write-back (SARIF / artifacts) |
A-02: GitHub Actions Infrastructure |
A-01: GitHub Repository (main / protected) |
HTTPS |
DF-23: Approved merge to main |
A-04: Release Gate / Code Review |
A-01: GitHub Repository (main / protected) |
|
DF-24: Publish wheel to PyPI (OIDC) |
A-02: GitHub Actions Infrastructure |
A-03: PyPI / TestPyPI |
HTTPS |
DF-25: pip install dfetch |
Consumer / End User |
A-03: PyPI / TestPyPI |
HTTPS |
DF-26: Consumer downloads dfetch from PyPI |
A-03: PyPI / TestPyPI |
Consumer / End User |
HTTPS |
Threats¶
ID |
Description |
Target |
Analysis |
Controls / Notes |
|---|---|---|---|---|
DFT-02 |
Supply-chain content substitution via server-side compromise |
A-03: PyPI / TestPyPI |
Sev: 🟠H
Risk: 🟠H
STRIDE: T S
Status: Mitigate
|
C-022 |
DFT-03 |
Path traversal in archive or patch extraction |
A-08: Python Build (wheel / sdist) |
Sev: 🔴VH
Risk: 🟡M
STRIDE: T E
Status: Mitigate
|
C-015, C-017 |
DFT-05 |
Mutable VCS reference enables silent content substitution |
DF-16: CI fetches build/dev deps from PyPI |
Sev: 🟡M
Risk: 🟡M
STRIDE: T S
Status: Mitigate
|
C-021 |
DFT-07 |
CI/CD secret exfiltration via supply-chain attack on build environment |
A-08: Python Build (wheel / sdist) |
Sev: 🟠H
Risk: 🟠H
STRIDE: S T I E
Status: Mitigate
|
C-009, C-010, C-011, C-012, C-013, C-024 |
DFT-08 |
Tampered secondary artifact suppresses or bypasses security checks |
A-08b: GitHub Actions Build Cache |
Sev: 🟡M
Risk: 🟠H
STRIDE: T
Status: Accept
|
Secondary artifacts are not independently verified in the supply-chain pipeline. Accepted based on the CI runner posture assumption: GitHub Actions environments run on ephemeral, GitHub-hosted runners whose isolation is provided by GitHub, so secondary artifacts written and consumed within a single job are considered adequately protected by that isolation. |
DFT-09 |
Archive decompression bomb causes resource exhaustion |
A-08: Python Build (wheel / sdist) |
Sev: 🟡M
Risk: 🟡M
STRIDE: D
Status: Accept
|
Decompression-bomb protection is a runtime concern (C-002 in usage model), not a supply-chain pipeline control. Accepted based on the CI runner posture assumption: GitHub Actions environments run on ephemeral, isolated runners; any denial-of-service impact from a decompression bomb is bounded to the affected job and does not persist beyond it. |
DFT-10 |
Build or development dependency substitution via compromised registry |
A-07: dfetch Build / Dev Dependencies |
Sev: 🟠H
Risk: 🟠H
STRIDE: T
Status: Mitigate
|
C-016 checks known-vulnerable deps on PRs; build deps lack |
DFT-11 |
Privileged account compromise enables unauthorised merge or release |
A-04: Release Gate / Code Review |
Sev: 🟠H
Risk: 🟠H
STRIDE: S E
Status: Accept
|
No hardware-token MFA or mandatory second-approver enforced for accounts with merge or release-trigger rights. Accepted based on the Trusted workstation assumption: developer workstations and accounts are trusted at development and commit time; a compromised maintainer account is outside the scope of this model. |
DFT-17 |
Typosquatting or unverified source identity on an unauthenticated channel |
A-03: PyPI / TestPyPI |
Sev: 🟠H
Risk: 🟡M
STRIDE: S
Status: Mitigate
|
C-026 |
DFT-18 |
Dependency confusion - public registry package shadows private internal package |
A-07: dfetch Build / Dev Dependencies |
Sev: 🟠H
Risk: 🟠H
STRIDE: T S
Status: Accept
|
Namespace-squatting on PyPI is a registry-level concern outside dfetch’s control. Accepted based on the CI runner posture assumption: GitHub Actions environments inherit the security posture of the GitHub-hosted runner, including its access to the public PyPI registry; registry-level namespace integrity is outside the scope of this model. |
DFT-20 |
Abandoned package namespace reclaimed by malicious actor |
A-07: dfetch Build / Dev Dependencies |
Sev: 🟠H
Risk: 🟡M
STRIDE: S T
Status: Accept
|
Abandoned namespace reclaim is a registry-level concern outside dfetch’s control. Accepted based on the CI runner posture assumption: GitHub Actions environments inherit the security posture of the GitHub-hosted runner, including its access to the public PyPI registry; registry-level namespace integrity is outside the scope of this model. |
DFT-23 |
Replay or freeze attack delivers stale content to suppress security updates |
DF-16: CI fetches build/dev deps from PyPI |
Sev: 🟡M
Risk: 🟡M
STRIDE: T
Status: Accept
|
No version-pinning or update-freshness check in the supply-chain pipeline. Accepted based on the CI runner posture assumption: GitHub Actions environments inherit the security posture of the GitHub-hosted runner; freshness enforcement for registry dependencies is a registry-level concern outside the scope of this model. |
DFT-24 |
Local dependency cache or metadata store poisoned to suppress integrity alerts |
A-08b: GitHub Actions Build Cache |
Sev: 🟠H
Risk: 🟠H
STRIDE: T
Status: Accept
|
Build-artifact cache is ref-scoped (C-033); pipeline metadata store is not independently integrity-protected. Accepted based on the CI runner posture assumption: GitHub Actions environments run on ephemeral, GitHub-hosted runners; the ref-scoped cache key isolation provided by that environment is considered sufficient for the pipeline metadata. |
DFT-25 |
Forged or unverifiable provenance attestation conceals malicious build output |
A-08b: GitHub Actions Build Cache |
Sev: 🟠H
Risk: 🟠H
STRIDE: S T R
Status: Mitigate
|
C-026, C-039 |
DFT-27 |
Build or release triggered from unofficial source fork or unprotected branch |
A-04: Release Gate / Code Review |
Sev: 🟠H
Risk: 🟠H
STRIDE: T S
Status: Mitigate
|
C-032 |
DFT-28 |
CI/CD build cache poisoned to silently substitute a malicious compiled artifact |
A-08b: GitHub Actions Build Cache |
Sev: 🟠H
Risk: 🟠H
STRIDE: T
Status: Mitigate
|
C-033 |
DFT-29 |
Signing key or short-lived publish credential exfiltrated from build environment |
A-08: Python Build (wheel / sdist) |
Sev: 🔴VH
Risk: 🟠H
STRIDE: I T
Status: Mitigate
|
C-013 |
DFT-31 |
Upstream source publishes no SLSA Source provenance attestation — consumer cannot verify upstream security controls |
DF-26: Consumer downloads dfetch from PyPI |
Sev: 🟡M
Risk: 🟢L
STRIDE: R S
Status: Mitigate
|
C-037, C-039, C-040 |
DFT-33 |
Upstream default-branch history rewritten — ancestry broken, pinned SHA orphaned or made unreachable |
DF-26: Consumer downloads dfetch from PyPI |
Sev: 🟡M
Risk: 🟢L
STRIDE: T
Status: Mitigate
|
C-038 |
Controls¶
ID |
Name |
Threats |
Description |
|---|---|---|---|
C-009 |
Actions commit-SHA pinning |
DFT-07 |
Every third-party GitHub Action is pinned to a full commit SHA, preventing tag-mutable supply-chain substitution. |
C-010 |
OIDC trusted publishing |
DFT-07 |
PyPI publishes via |
C-011 |
Minimal workflow permissions |
DFT-07 |
Each workflow declares only the permissions it requires (default |
C-012 |
persist-credentials: false |
DFT-07 |
|
C-013 |
Harden-runner (egress block) |
DFT-07, DFT-29 |
|
C-015 |
CodeQL static analysis |
DFT-03, DFT-06 |
CodeQL scans the Python codebase for security vulnerabilities on pushes and pull requests targeting |
C-016 |
Dependency review |
DFT-10 |
|
C-017 |
bandit security linter |
DFT-03, DFT-06 |
|
C-021 |
Sigstore SBOM attestation |
DFT-05 |
The release pipeline generates CycloneDX SBOM attestations via |
C-022 |
CycloneDX SBOM on PyPI |
DFT-02 |
A CycloneDX SBOM is generated during the build and published alongside the PyPI release, satisfying CRA Article 13 requirements. |
C-024 |
|
DFT-07 |
|
C-026 |
Consumer-side package provenance verification |
DFT-17, DFT-25 |
Consumers installing dfetch via |
C-032 |
Consumer attestation verification pins to release tag ref |
DFT-27 |
All |
C-033 |
Ref-scoped build cache keys isolate PR and release builds |
DFT-28 |
ccache and clcache keys in |
C-037 |
SLSA Source Provenance Attestation of repository governance controls |
DFT-31 |
Source Provenance Attestations are published via |
C-038 |
Ancestry enforcement on dfetch main branch |
DFT-33 |
GitHub branch-protection rules on the dfetch |
C-039 |
Source build provenance and VSA attestations |
DFT-31, DFT-25 |
Every dfetch release ships two complementary Sigstore-signed attestations that together let consumers trace the full source → binary chain. SLSA build provenance ( |
C-040 |
Test result attestation on source archive |
DFT-31 |
The CI test workflow ( |