diff --git a/.github/workflows/source-provenance.yml b/.github/workflows/source-provenance.yml index 957809537..e54d6a460 100644 --- a/.github/workflows/source-provenance.yml +++ b/.github/workflows/source-provenance.yml @@ -41,7 +41,7 @@ jobs: persist-credentials: true - name: Attest source governance (SLSA Source Track) - uses: slsa-framework/source-actions/slsa_with_provenance@v0.1.0 + uses: slsa-framework/source-actions/slsa_with_provenance@dea965cdca5e0cb422bf7b2653c9d15f678ad01c # v0.1.0 with: version: v0.6.3 diff --git a/dfetch/util/cmdline.py b/dfetch/util/cmdline.py index edecc4e12..89e136302 100644 --- a/dfetch/util/cmdline.py +++ b/dfetch/util/cmdline.py @@ -46,8 +46,8 @@ def run_on_cmdline( logger.debug(f"Running {cmd}") try: - proc = subprocess.run( # nosec - cmd, env=env, input=input_data, capture_output=True, check=True + proc = subprocess.run( # nosec B603 — shell=False, list-form args from internal code + cmd, shell=False, env=env, input=input_data, capture_output=True, check=True ) except subprocess.CalledProcessError as exc: raise SubprocessCommandError( diff --git a/doc/explanation/compliance_track.rst b/doc/explanation/compliance_track.rst index 7049097c3..c88420d75 100644 --- a/doc/explanation/compliance_track.rst +++ b/doc/explanation/compliance_track.rst @@ -141,7 +141,7 @@ The table below summarises dfetch's implementation of each prEN 40000-1-4 Securi * - **ECR-C** — Ensure that vulnerabilities can be addressed through security updates, including automatic updates enabled by default, with an opt-out mechanism, user notification, and the option to postpone updates. - SO.Updateability - — - - — + - Satisfied by pip distribution (``pip install --upgrade dfetch``); no dfetch-specific control required — see note below table. - ✓ Implemented * - - SO.AutomaticUpdates @@ -165,7 +165,7 @@ The table below summarises dfetch's implementation of each prEN 40000-1-4 Securi - ⚠ Partial * - - SO.AccessControlReport - - :ref:`C-009 ` + - :ref:`C-045 ` - No persistent log of unauthorised access attempts - ⚠ Partial * - **ECR-E** — Protect the confidentiality of stored, transmitted or otherwise processed data by state-of-the-art mechanisms such as encryption at rest and in transit. @@ -180,12 +180,12 @@ The table below summarises dfetch's implementation of each prEN 40000-1-4 Securi - ✓ Implemented * - - SO.DataTransmittedConfidentiality - - :ref:`C-005 `, :ref:`C-009 ` + - :ref:`C-005 `, :ref:`C-045 ` - — - ✓ Implemented * - - SO.ComAuth - - :ref:`C-003 `, :ref:`C-004 `, :ref:`C-009 ` + - :ref:`C-003 `, :ref:`C-004 `, :ref:`C-045 ` - — - ✓ Implemented * - @@ -210,7 +210,7 @@ The table below summarises dfetch's implementation of each prEN 40000-1-4 Securi - ⚠ Partial * - - SO.IntegrityReport - - :ref:`C-009 ` + - :ref:`C-045 ` - No persistent integrity-violation log - ⚠ Partial * - **ECR-G** — Process only data, personal or other, that are adequate, relevant and limited to what is necessary in relation to the intended purpose of the product with digital elements (data minimisation). @@ -260,7 +260,7 @@ The table below summarises dfetch's implementation of each prEN 40000-1-4 Securi - ⚠ Partial * - - SO.MonitorSecurityRelevantActivities - - :ref:`C-009 ` + - :ref:`C-045 ` - — - ⚠ Partial * - @@ -276,7 +276,7 @@ The table below summarises dfetch's implementation of each prEN 40000-1-4 Securi * - **ECR-M** — Provide the possibility for users to securely and easily remove on a permanent basis all data and settings and, where such data can be transferred to other products or systems, ensure that this is done in a secure manner. - SO.SecureDataDeletion - — - - — + - No dfetch-specific control required — satisfied by design (no personal data stored); standard OS file deletion suffices — see note below table. - ✓ Implemented * - - SO.DataTransmittedConfidentiality @@ -294,6 +294,21 @@ The table below summarises dfetch's implementation of each prEN 40000-1-4 Securi - — - — N/A +.. rubric:: Notes on "Implemented" rows with no control listed + +**ECR-C SO.Updateability** — No dfetch-specific control is needed. SUM-1/SUM-2 +are satisfied by the PyPI distribution mechanism (``pip install --upgrade dfetch`` +and GitHub Releases binary packages). pip's TLS-protected download channel provides +the required secure update path. The update mechanism is the responsibility of the +user's package manager, not of dfetch itself. + +**ECR-M SO.SecureDataDeletion** — No dfetch-specific control is needed. DLM-1 is +satisfied by design: dfetch stores no personal data, credentials, or cryptographic +keying material on disk. The only on-disk state is ``.dfetch_data.yaml`` (non-sensitive +dependency metadata — credentials stripped by :ref:`C-036 `) and vendored +source files (third-party code). Standard OS file deletion (``rm`` / ``del``) is +sufficient to remove all dfetch data; no secure-wipe facility is warranted. + ---- Part II — Vulnerability Handling (prEN 40000-1-3) diff --git a/doc/explanation/control_register.rst b/doc/explanation/control_register.rst index c12825c5c..67ce020d3 100644 --- a/doc/explanation/control_register.rst +++ b/doc/explanation/control_register.rst @@ -127,9 +127,9 @@ requirements not independently surfaced by the risk analysis. * - .. _c-024: C-024 - - ``secrets: inherit`` scope + - Explicit secret forwarding - Risk-driven - - — + - `.github/workflows/ci.yml `_ * - .. _c-026: C-026 @@ -208,6 +208,13 @@ requirements not independently surfaced by the risk analysis. - Data minimisation policy - Compliance-only - :doc:`compliance_track` + * - .. _c-045: + + C-045 + - Plaintext transport detection + - Risk-driven + - `dfetch/manifest/project.py `_, + `dfetch/project/subproject.py `_ * - .. _c-046: C-046 diff --git a/doc/explanation/security.rst b/doc/explanation/security.rst index bae0fbe5f..87147988d 100644 --- a/doc/explanation/security.rst +++ b/doc/explanation/security.rst @@ -108,6 +108,61 @@ For an overview of how this documentation set is produced — the threat-model pipeline, compliance pipeline, release attestations, and the full artifact inventory — see :doc:`security_pipeline`. +.. _risk-rating-methodology: + +Risk Rating Methodology +----------------------- + +Both threat models use a qualitative two-axis risk framework aligned with +`BSI TR-03183-1 §5.3 `_ +(Cyber Resilience Requirements for Manufacturers, Chapter 5). + +Each threat entry carries two independent ratings: + +**Severity (Sev)** — the maximum potential impact if the threat is fully +realised, assessed without regard to likelihood or existing controls. +Determined from the Confidentiality / Integrity / Availability ratings of +the targeted asset and the scope of harm to downstream consumers. + +**Risk** — the *residual* risk after factoring in the likelihood of +successful exploitation (attacker capability, required access, known +exploitation evidence) and any controls already partially in place. +Risk can therefore be lower than Severity when the attack path is +constrained, and must be reassessed whenever the control set changes. + +.. list-table:: + :header-rows: 1 + :widths: 12 20 68 + + * - Rating + - Label + - Guidance (BSI TR-03183-1 §5.3) + + * - 🟢L + - Low + - Negligible impact or extremely unlikely. No mandatory control action; document and monitor. + + * - 🟡M + - Medium + - Moderate impact or realistic but non-trivial exploit path. Controls advisable; track in backlog. + + * - 🟠H + - High + - Significant impact or credible attack path with meaningful probability. Controls required before next release. + + * - 🔴VH + - Very High + - Severe impact (system compromise, data exfiltration) or well-documented exploit path. Priority controls required. + + * - 🔴C + - Critical + - Catastrophic, near-certain potential (e.g. unencrypted channel with no compensating control). Immediate mitigation required; accept decision requires explicit sign-off. + +The risk treatment decisions (Mitigate / Accept / Transfer) in each threat +table follow the same vocabulary as ISO/IEC 27005 and BSI TR-03183-1: an +**Accept** decision requires explicit rationale citing the assumption under +which the residual risk is acceptable, documented alongside the threat entry. + Threat Models ------------- diff --git a/doc/explanation/threat_model_supply_chain.rst b/doc/explanation/threat_model_supply_chain.rst index 047d8f8c8..bae0c9d92 100644 --- a/doc/explanation/threat_model_supply_chain.rst +++ b/doc/explanation/threat_model_supply_chain.rst @@ -17,6 +17,8 @@ Risk Context This report follows the risk-based approach of `BSI TR-03183-1 `_ Chapter 5. +The Sev / Risk rating scale and treatment vocabulary (Mitigate / Accept / Transfer) +are defined in the :ref:`Risk Rating Methodology ` section of the main security page. Threat model for dfetch. Covers the pre-install lifecycle: code contribution, CI/CD, build (wheel / sdist), PyPI distribution, Winget manifest submission, and consumer installation. The installed dfetch package is the handoff point to tm_usage.py. @@ -879,7 +881,7 @@ Controls * - 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. ``.github/workflows/*.yml`` + - All third-party GitHub Actions are pinned to a full commit SHA (``@<40-hex>``), preventing tag-mutable supply-chain substitution. ``.github/workflows/*.yml`` * - C-010 - OIDC trusted publishing - DFT-07 @@ -917,9 +919,9 @@ Controls - DFT-02 - A CycloneDX SBOM is generated during the build and published alongside the PyPI release, satisfying CRA Article 13 requirements. * - C-024 - - ``secrets: inherit`` scope + - Explicit secret forwarding - DFT-07 - - ``ci.yml`` only passes required repository secrets to the test and docs workflows, preventing malicious PR steps from exfiltrating unrelated secrets. + - ``ci.yml`` explicitly names only the secrets each child workflow requires (``CODACY_PROJECT_TOKEN`` → ``test.yml``; ``GH_DFETCH_ORG_DEPLOY`` → ``docs.yml``); all other repository secrets are not forwarded. ``secrets: inherit`` is deliberately not used so that malicious PR steps cannot exfiltrate unrelated secrets. ``.github/workflows/ci.yml`` * - C-026 - Consumer-side package provenance verification - DFT-17, DFT-25 diff --git a/doc/explanation/threat_model_usage.rst b/doc/explanation/threat_model_usage.rst index cc19a5f6a..5163cf324 100644 --- a/doc/explanation/threat_model_usage.rst +++ b/doc/explanation/threat_model_usage.rst @@ -17,6 +17,8 @@ Risk Context This report follows the risk-based approach of `BSI TR-03183-1 `_ Chapter 5. +The Sev / Risk rating scale and treatment vocabulary (Mitigate / Accept / Transfer) +are defined in the :ref:`Risk Rating Methodology ` section of the main security page. Threat model for dfetch. Covers the post-install lifecycle: reading the manifest, fetching dependencies from VCS and archive sources, applying patches, writing vendored files, and generating reports (SBOM, SARIF, check output). The installed dfetch package - produced by the supply chain in tm_supply_chain.py - is the entry point. @@ -1013,7 +1015,7 @@ Threats | **Risk:** 🟠H | **STRIDE:** T | **Status:** Accept - - Git submodules are followed: ``git submodule update --init --recursive`` is called unconditionally during every Git fetch (``dfetch/vcs/git.py``), and each submodule is recorded as a ``Dependency`` with ``source_type='git-submodule'`` (``gitsubproject.py``). SVN ``export`` is invoked without ``--ignore-externals``; each ``svn:externals`` entry triggers an additional fetch, and ``SvnSubProject._fetch_externals()`` records it as a ``Dependency`` with ``source_type='svn-external'`` (``svnsubproject.py``). Both behaviours are intentional — dfetch vendors submodule and external trees and surfaces them in metadata — but the fetched URLs come from the upstream repository (``.gitmodules`` / ``svn:externals``), not from ``dfetch.yaml``, and therefore bypass manifest code review and carry no integrity hash. Suppressing these fetches (e.g. passing ``--no-recurse-submodules`` or ``--ignore-externals``) would be a design change that removes intentional vendoring behaviour. Accepted based on the **Manifest under code review** assumption: the choice to vendor an upstream that contains submodules or svn:externals is declared in ``dfetch.yaml`` and subject to code review; the decision to trust those nested URLs is made at the manifest-review boundary. + - Git submodules are followed: ``git submodule update --init --recursive`` is called unconditionally during every Git fetch (``dfetch/vcs/git.py``), and each submodule is recorded as a ``Dependency`` with ``source_type='git-submodule'`` (``gitsubproject.py``). SVN ``export`` is invoked without ``--ignore-externals``; each ``svn:externals`` entry triggers an additional fetch, and ``SvnSubProject._fetch_externals()`` records it as a ``Dependency`` with ``source_type='svn-external'`` (``svnsubproject.py``). Both behaviours are intentional — dfetch vendors submodule and external trees and surfaces them in metadata — but the fetched URLs come from the upstream repository (``.gitmodules`` / ``svn:externals``), not from ``dfetch.yaml``, and therefore bypass manifest code review and carry no integrity hash. Suppressing these fetches (e.g. passing ``--no-recurse-submodules`` or ``--ignore-externals``) would be a design change that removes intentional vendoring behaviour. The initial decision to vendor a given upstream repository (which may contain submodules or SVN externals) is declared in ``dfetch.yaml`` and subject to code review. However, the specific nested URLs in ``.gitmodules`` or ``svn:externals`` are not visible in ``dfetch.yaml`` and are not independently reviewed; if an upstream maintainer adds a new submodule after the initial review, dfetch will fetch it on the next ``dfetch update`` without a new ``dfetch.yaml`` change triggering review. Residual risk: a compromised upstream maintainer could inject a malicious submodule URL that bypasses the manifest review boundary. Accepted based on the **dfetch scope boundary** assumption: the security of fetched third-party source code and its nested dependencies is the responsibility of the manifest author who selects and pins each upstream; ``dfetch check`` version-drift notifications prompt review before any upstream change (including new submodules) is vendored. * - DFT-16 - Configured destination path allows writes to security-sensitive project directories - A-22: dfetch Process @@ -1101,7 +1103,7 @@ Threats | **Risk:** 🟠H | **STRIDE:** T I | **Status:** Mitigate - - C-009 emits a visible warning immediately before the VCS command when a plaintext scheme (``http://``, ``git://``, ``svn://``) is detected, with credentials redacted and ``https://`` / ``svn+ssh://`` recommended. Detection only — dfetch does not reject or upgrade plaintext URLs; scheme selection remains the manifest author's responsibility. + - C-045 emits a visible warning immediately before the VCS command when a plaintext scheme (``http://``, ``git://``, ``svn://``) is detected, with credentials redacted and ``https://`` / ``svn+ssh://`` recommended. Detection only — dfetch does not reject or upgrade plaintext URLs; scheme selection remains the manifest author's responsibility. * - DFT-28 - CI/CD build cache poisoned to silently substitute a malicious compiled artifact - A-20: Local VCS Cache (temp) @@ -1188,7 +1190,7 @@ Controls - Manifest input validation - DFT-04, DFT-08 - StrictYAML schema with ``SAFE_STR = Regex(r"^[^\x00-\x1F\x7F-\x9F]*$")`` rejects control characters in all string fields. ``dfetch/manifest/schema.py`` - * - C-009 + * - C-045 - Plaintext transport detection - DFT-26 - ``plaintext_warning()`` (``dfetch/manifest/project.py``) inspects the resolved remote URL immediately before each VCS command is issued (inside the ``check_for_update`` and ``update`` spinners in ``subproject.py``). If the scheme is ``http://``, ``git://``, or ``svn://``, a visible warning is emitted naming the redacted URL (credentials stripped from the userinfo component) and recommending ``https://`` or ``svn+ssh://``. Detection only — dfetch still proceeds with the plaintext connection; the control raises user awareness but does not enforce scheme selection. ``dfetch/manifest/project.py, dfetch/project/subproject.py`` diff --git a/security/compliance_data.py b/security/compliance_data.py index c1690de55..072677d31 100644 --- a/security/compliance_data.py +++ b/security/compliance_data.py @@ -225,10 +225,18 @@ class PartIIRequirement: SOImplementation( so_id="so-updateability", ecr_id="ecr-c", + not_applicable=[ + "No dfetch-specific control required — updateability is inherent to " + "pip distribution (``pip install --upgrade dfetch``) and GitHub Releases. " + "SUM-1/SUM-2 are satisfied by the distribution mechanism, not by a " + "runtime dfetch feature." + ], status="implemented", description=( - "SUM-1/SUM-2: Updates distributed via PyPI (pip install --upgrade dfetch) " - "and GitHub Releases. pip's TLS-protected download satisfies SUM-2." + "SUM-1/SUM-2: Updates distributed via PyPI (``pip install --upgrade dfetch``) " + "and GitHub Releases. pip's TLS-protected download and version-pinning " + "model satisfies SUM-2. No dfetch-specific update mechanism is needed or " + "implemented; the package manager is the update vehicle." ), ), SOImplementation( @@ -278,11 +286,11 @@ class PartIIRequirement: SOImplementation( so_id="so-access-control-report", ecr_id="ecr-d", - controls=["C-009"], + controls=["C-045"], gaps=["No persistent log of unauthorised access attempts"], status="partially-implemented", description=( - "GEC-13: C-009 (plaintext transport warning) alerts on unauthenticated " + "GEC-13: C-045 (plaintext transport warning) alerts on unauthenticated " "connections. No persistent security event log." ), ), @@ -315,14 +323,14 @@ class PartIIRequirement: SOImplementation( so_id="so-data-transmitted-confidentiality", ecr_id="ecr-e", - controls=["C-005", "C-009"], + controls=["C-005", "C-045"], status="implemented", description=( "SCM-3/SCM-4: Plaintext transport (http://, git://, svn://) is accepted " - "by design for legacy source compatibility. C-009 detects and warns the " + "by design for legacy source compatibility. C-045 detects and warns the " "user before proceeding — 'Detection only; dfetch still proceeds with the " "plaintext connection; the control raises user awareness but does not " - "enforce scheme selection' (usage threat model, C-009 description). " + "enforce scheme selection' (usage threat model, C-045 description). " "For archive URLs over HTTP, C-005 (integrity hash) verifies that content " "has not been tampered with in transit; it does not encrypt or conceal the " "content. This is a deliberate design decision, not a residual gap." @@ -331,14 +339,14 @@ class PartIIRequirement: SOImplementation( so_id="so-com-auth-e", ecr_id="ecr-e", - controls=["C-003", "C-004", "C-009"], + controls=["C-003", "C-004", "C-045"], status="implemented", description=( "SCM-2: HTTPS connections authenticate via TLS CA chain (C-003); SSH " "connections authenticate via host-key verification (C-004). Plain git:// " "and svn:// connections lack channel-level authentication but are accepted " "by design for legacy compatibility — the same rationale as " - "DataTransmittedConfidentiality — and C-009 warns the user. The usage " + "DataTransmittedConfidentiality — and C-045 warns the user. The usage " "threat model notes the network adversary 'cannot break correctly " "implemented TLS or SSH'; the residual risk for unauthenticated transports " "is an accepted design trade-off." @@ -390,11 +398,11 @@ class PartIIRequirement: SOImplementation( so_id="so-integrity-report", ecr_id="ecr-f", - controls=["C-009"], + controls=["C-045"], gaps=["No persistent integrity-violation log"], status="partially-implemented", description=( - "GEC-13-f: dfetch surfaces transport-integrity warnings (C-009) at runtime " + "GEC-13-f: dfetch surfaces transport-integrity warnings (C-045) at runtime " "but does not maintain a persistent security event log." ), ), @@ -530,11 +538,11 @@ class PartIIRequirement: SOImplementation( so_id="so-monitor-security-relevant-activities", ecr_id="ecr-l", - controls=["C-009"], + controls=["C-045"], not_applicable=["NMM-1 (no ambient network monitoring)"], status="partially-implemented", description=( - "MON-1: C-009 (plaintext transport detection) monitors for insecure " + "MON-1: C-045 (plaintext transport detection) monitors for insecure " "connections at runtime and surfaces warnings to the user." ), ), @@ -556,13 +564,22 @@ class PartIIRequirement: SOImplementation( so_id="so-secure-data-deletion", ecr_id="ecr-m", + not_applicable=[ + "No dfetch-specific secure-deletion control is required: dfetch stores " + "no personal data and no keying material. The only on-disk state is " + ".dfetch_data.yaml (non-sensitive metadata) and vendored source files " + "(third-party code, not user data). Standard OS file deletion (rm / del) " + "is sufficient; cryptographic wipe is not warranted. DLM-1 is satisfied " + "by design (no sensitive data to wipe), not by a dedicated dfetch control." + ], status="implemented", description=( "DLM-1: .dfetch_data.yaml contains only non-sensitive metadata — " "remote URL (credentials stripped by C-036), revision, optional content " - "hash, and last-fetch timestamp. Standard OS file deletion (rm / del) is " - "sufficient; no secure-wipe is required. Users delete the file and " - "vendored directories to remove all dfetch data." + "hash, and last-fetch timestamp. Standard OS file deletion is sufficient; " + "no secure-wipe is required. Users delete the file and vendored directories " + "to remove all dfetch data. ECR-m is satisfied by design because dfetch " + "collects no personal data, credentials, or keying material on disk." ), ), SOImplementation( diff --git a/security/report_template.rst b/security/report_template.rst index 20cbeefa7..33410c52b 100644 --- a/security/report_template.rst +++ b/security/report_template.rst @@ -14,6 +14,8 @@ Risk Context This report follows the risk-based approach of `BSI TR-03183-1 `_ Chapter 5. +The Sev / Risk rating scale and treatment vocabulary (Mitigate / Accept / Transfer) +are defined in the :ref:`Risk Rating Methodology ` section of the main security page. {tm.description} diff --git a/security/tm_supply_chain.py b/security/tm_supply_chain.py index 907f4c241..0fac73b24 100644 --- a/security/tm_supply_chain.py +++ b/security/tm_supply_chain.py @@ -717,8 +717,8 @@ def build_model() -> TM: threats=["DFT-07"], reference=".github/workflows/*.yml", description=( - "Every third-party GitHub Action is pinned to a full commit SHA, " - "preventing tag-mutable supply-chain substitution." + "All third-party GitHub Actions are pinned to a full commit SHA " + "(``@<40-hex>``), preventing tag-mutable supply-chain substitution." ), ), Control( @@ -827,13 +827,15 @@ def build_model() -> TM: ), Control( id="C-024", - name="``secrets: inherit`` scope", + name="Explicit secret forwarding", assets=["A-01", "A-05"], threats=["DFT-07"], description=( - "``ci.yml`` only passes required repository secrets to the test and " - "docs workflows, preventing malicious PR steps from exfiltrating " - "unrelated secrets." + "``ci.yml`` explicitly names only the secrets each child workflow " + "requires (``CODACY_PROJECT_TOKEN`` → ``test.yml``; " + "``GH_DFETCH_ORG_DEPLOY`` → ``docs.yml``); all other repository " + "secrets are not forwarded. ``secrets: inherit`` is deliberately " + "not used so that malicious PR steps cannot exfiltrate unrelated secrets." ), ), Control( diff --git a/security/tm_usage.py b/security/tm_usage.py index d9dd80c3e..d5142c57b 100644 --- a/security/tm_usage.py +++ b/security/tm_usage.py @@ -966,7 +966,7 @@ def build_model() -> TM: ), ), Control( - id="C-009", + id="C-045", name="Plaintext transport detection", assets=["A-09", "A-22"], threats=["DFT-26"], @@ -1192,10 +1192,20 @@ def build_model() -> TM: "Suppressing these fetches (e.g. passing ``--no-recurse-submodules`` or " "``--ignore-externals``) would be a design change that removes intentional " "vendoring behaviour. " - "Accepted based on the **Manifest under code review** assumption: the choice " - "to vendor an upstream that contains submodules or svn:externals is declared in " - "``dfetch.yaml`` and subject to code review; the decision to trust those " - "nested URLs is made at the manifest-review boundary." + "The initial decision to vendor a given upstream repository (which may " + "contain submodules or SVN externals) is declared in ``dfetch.yaml`` and " + "subject to code review. However, the specific nested URLs in " + "``.gitmodules`` or ``svn:externals`` are not visible in ``dfetch.yaml`` " + "and are not independently reviewed; if an upstream maintainer adds a new " + "submodule after the initial review, dfetch will fetch it on the next " + "``dfetch update`` without a new ``dfetch.yaml`` change triggering review. " + "Residual risk: a compromised upstream maintainer could inject a malicious " + "submodule URL that bypasses the manifest review boundary. " + "Accepted based on the **dfetch scope boundary** assumption: the security " + "of fetched third-party source code and its nested dependencies is the " + "responsibility of the manifest author who selects and pins each upstream; " + "``dfetch check`` version-drift notifications prompt review before any " + "upstream change (including new submodules) is vendored." ), target="A-27: Git Clone (git init / fetch / checkout)", ), @@ -1358,7 +1368,7 @@ def build_model() -> TM: risk="High", stride=["Tampering", "Information Disclosure"], note=( - "C-009 emits a visible warning immediately before the VCS command when a " + "C-045 emits a visible warning immediately before the VCS command when a " "plaintext scheme (``http://``, ``git://``, ``svn://``) is detected, " "with credentials redacted and ``https://`` / ``svn+ssh://`` recommended. " "Detection only — dfetch does not reject or upgrade plaintext URLs; "