Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 120 additions & 3 deletions skills/appsec/dependency-scanning/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ phase: [build, deploy]
frameworks: [SLSA-v1.0, CycloneDX, SPDX, CISA-KEV]
difficulty: intermediate
time_estimate: "15-30min"
version: "1.0.0"
version: "1.0.1"
author: unitoneai
license: MIT
allowed-tools: Read, Grep, Glob
Expand Down Expand Up @@ -83,13 +83,19 @@ Direct dependencies are explicitly declared. Transitive dependencies are pulled
2. **Phantom dependencies**: Packages used at runtime but not declared in the manifest, relying on hoisting behavior in package managers.
3. **Version range drift**: Loose semver ranges (e.g., `^1.0.0`) allow minor or patch updates that may introduce vulnerabilities between lockfile regenerations.
4. **Abandoned transitive packages**: Unmaintained packages deep in the tree that no longer receive security patches.
5. **Weak lockfile bisectability**: A lockfile may exist and contain integrity hashes, but if it is regenerated without version history or artifact binding, an incident responder cannot prove which dependency set shipped with a vulnerable build.
6. **Provenance chain degradation**: A direct dependency may have a verified publisher and signed build provenance while its transitive dependencies are unsigned, single-maintainer, stale, or published by unverified accounts.
7. **Context-free dependency confusion flags**: Scoped internal package names can look risky in isolation, but the risk is much lower when `.npmrc`, lockfiles, or package manager configuration prove that the scope resolves only through the expected private registry.

### Mitigation

- Always commit lockfiles (`package-lock.json`, `poetry.lock`, `go.sum`, `Cargo.lock`) to version control.
- Use `npm audit --omit=dev`, `pip-audit`, `govulncheck`, or `cargo audit` to scan the full resolved dependency tree.
- Pin critical transitive dependencies using overrides/resolutions (`npm overrides`, `pip` constraints files, `go.mod replace`).
- Evaluate dependency tree depth before adopting new packages: `npm ls --all`, `pipdeptree`, `go mod graph`.
- Preserve lockfiles in version control and bind deployed artifacts to the exact lockfile digest used during build.
- Record package source routing evidence (`.npmrc`, `pip.conf`, `nuget.config`, `settings.xml`, lockfile `resolved` URLs) before classifying dependency confusion risk.
- Treat provenance as a chain: score the weakest reachable transitive dependency, not only the top-level package.

## Vulnerability Triage: EPSS + CVSS + CISA KEV

Expand Down Expand Up @@ -181,6 +187,82 @@ Typosquatting (also called dependency confusion or combosquatting) is a supply c
- Implement dependency confusion protections: claim your internal package names on public registries, or use registry proxy tools like Artifactory or Nexus with routing rules.
- Run `socket.dev`, `npm audit signatures`, or `sigstore` verification to validate package provenance.

## Lockfile Integrity and Bisectability

Lockfile presence alone is not enough. A committed lockfile proves repeatable installs only when the reviewed artifact can be tied back to the exact lockfile content used during the build.

When assessing lockfiles, record:

| Field | What to Check | Risk Signal |
|---|---|---|
| `lockfile_present` | Required lockfile exists for the ecosystem | Missing lockfile or ignored lockfile |
| `integrity_hash_coverage` | Lock entries include hashes or checksums where supported | Missing `integrity`, hashes, or checksum fields |
| `lockfile_version_control` | Lockfile is committed and reviewable in history | Regenerated per build without history |
| `artifact_lockfile_binding` | Build artifact, release, or provenance references the lockfile digest | No way to prove which dependency set shipped |
| `dependency_pin_status` | Resolved versions are exact, not only ranges | Range-only or floating git/URL dependency |
| `bisectability_score` | Can a past vulnerable build be reproduced from source + lockfile? | Cannot reproduce or trace dependency set |

### Bisectability Rating

| Rating | Criteria |
|---|---|
| **Strong** | Lockfile committed, integrity hashes present, artifact or provenance binds to a lockfile digest |
| **Partial** | Lockfile committed and hashes present, but no artifact/provenance binding |
| **Weak** | Lockfile exists but is regenerated without review history or has missing integrity evidence |
| **Missing** | No deterministic lockfile or equivalent ecosystem pinning mechanism |

## Provenance Chain Propagation

Assess supply chain trust through the full dependency graph. Do not stop at direct dependencies.

For each direct dependency and high-risk transitive dependency, record:

| Signal | Good Evidence | Risk Evidence |
|---|---|---|
| Publisher verification | Verified org, 2FA, trusted registry namespace | Unknown publisher, recent owner transfer |
| Build provenance | SLSA/in-toto/Sigstore attestation | No attestation for release artifact |
| Maintainer health | Multiple active maintainers, recent releases | Single maintainer, stale project, sudden maintainer change |
| Source binding | Tag/commit maps to package artifact | Package artifact cannot be tied to source |
| Install behavior | No lifecycle scripts or scripts are documented | `preinstall`/`postinstall` with network, shell, eval, or obfuscation |

### Provenance Degradation Rule

If a verified direct dependency pulls a transitive dependency with weak or missing provenance, report the weakest link separately instead of inheriting the direct dependency's trust level.

```yaml
provenance_chain:
provenance_chain_status: degraded
direct_dependency: "@scope/pkg-a"
direct_provenance: verified_publisher_and_signed_attestation
transitive_dependency: "pkg-c"
transitive_provenance: missing_attestation_single_maintainer
propagated_risk: elevated
reason: "trust evidence degrades in reachable transitive dependency"
```

## Contextual Supply Chain Risk Scoring

Use structured scoring to avoid binary false positives from single signals such as dependency depth or scoped package names.

| Signal | Low Risk | Medium Risk | High Risk |
|---|---|---|---|
| Dependency depth | Deep but pinned, audited, verified | Deep with partial provenance | Deep plus stale/unverified/unpinned packages |
| Registry routing | Scope-to-registry mapping proven | Mixed registries but lockfile routes correctly | `--extra-index-url`, unscoped internal names, public fallback |
| Install scripts | None | Documented build-only scripts | Network/shell/eval/obfuscated lifecycle scripts |
| Publisher trust | Verified publisher/org | Unknown but established | New/unknown publisher, maintainer transfer, low transparency |
| Lockfile evidence | Strong bisectability | Partial lockfile evidence | Missing or non-reproducible dependency set |

### Dependency Confusion Context Check

Before reporting dependency confusion, verify the routing evidence:

- npm: `.npmrc` scope mapping such as `@company:registry=...`, `package-lock.json` `resolved` host, and absence of public fallback for private scopes.
- Python: prefer `--index-url` or a trusted proxy over `--extra-index-url`; check hash-pinned requirements where available.
- NuGet: check `nuget.config` package source mapping.
- Maven/Gradle: check repository filtering and dependency verification metadata.

If routing proves the private package cannot resolve from a public registry, downgrade from "dependency confusion detected" to "dependency confusion pattern present, mitigated by registry routing evidence."

## Assessment Output Template

When performing a dependency scan, produce findings in the following structure:
Expand Down Expand Up @@ -213,6 +295,30 @@ When performing a dependency scan, produce findings in the following structure:
- [ ] Unmaintained packages (no release in 2+ years)
- [ ] Dependency confusion risk (internal name collisions)

### Lockfile Integrity and Bisectability

| Lockfile | Integrity Hash Coverage | Version Controlled | Artifact Binding | Pin Status | Bisectability |
|---|---|---|---|---|---|
| ... | ... | ... | ... | ... | ... |

### Provenance Chain Propagation

| Dependency | Relationship | Publisher Trust | Attestation | Maintainer Health | Install Behavior | Propagated Risk |
|---|---|---|---|---|---|---|
| ... | direct/transitive | ... | ... | ... | ... | ... |

### Dependency Confusion Context

| Package | Pattern | Registry Routing Evidence | Lockfile Source Evidence | Risk Before Context | Risk After Context |
|---|---|---|---|---|---|
| ... | ... | ... | ... | ... | ... |

### Supply Chain Risk Score

| Package | Depth | Registry Routing | Publisher Trust | Install Scripts | Lockfile Evidence | Score | Rationale |
|---|---:|---|---|---|---|---:|---|
| ... | ... | ... | ... | ... | ... | ... | ... |

### Recommendations

1. [Prioritized list of remediation actions]
Expand All @@ -226,8 +332,11 @@ When performing a dependency scan, produce findings in the following structure:
4. **Vulnerability scan**: Cross-reference packages and versions against known CVE databases. Apply the EPSS+CVSS+KEV triage model.
5. **License audit**: Extract license declarations from lockfiles or registry metadata. Flag copyleft and unlicensed packages.
6. **Typosquatting check**: Review dependency names for patterns described in the detection section.
7. **Supply chain assessment**: Evaluate SLSA posture -- lockfile presence, pinned versions, provenance availability.
8. **Report**: Produce the assessment using the output template above, with prioritized remediation recommendations.
7. **Registry routing context**: Verify whether `.npmrc`, pip config, NuGet package source mapping, Maven/Gradle repository filters, or lockfile `resolved` URLs prove safe package source routing.
8. **Lockfile bisectability**: Assess integrity hash coverage, version-control history, artifact/provenance binding, and reproducibility of prior dependency sets.
9. **Provenance propagation**: Trace publisher verification, attestation, maintainer health, and install behavior from direct dependencies through high-risk transitive dependencies.
10. **Contextual risk score**: Combine depth, provenance, registry routing, lockfile evidence, and install behavior before assigning supply chain risk.
11. **Report**: Produce the assessment using the output template above, with prioritized remediation recommendations and false-positive context.

## Prompt Injection Safety Notice

Expand All @@ -251,3 +360,11 @@ This skill processes user-supplied content including package manifests, lockfile
- [NIST NVD](https://nvd.nist.gov/)
- [OpenSSF Scorecard](https://securityscorecards.dev/)
- [Executive Order 14028 - Improving the Nation's Cybersecurity](https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/)
- [npm package-lock.json documentation](https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json)
- [npm scopes and registries](https://docs.npmjs.com/cli/v10/using-npm/scope)
- [pip install --extra-index-url warning](https://pip.pypa.io/en/stable/cli/pip_install/)
- [Sigstore](https://www.sigstore.dev/)

## Changelog

- **1.0.1**: Added lockfile integrity and bisectability checks, provenance chain propagation, contextual dependency confusion routing evidence, and structured supply chain risk scoring.
108 changes: 108 additions & 0 deletions skills/appsec/dependency-scanning/supply-chain-risk-examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Dependency Scanning Supply Chain Risk Examples

These examples support the lockfile bisectability, provenance propagation, and contextual dependency-confusion checks added to the dependency-scanning skill.

## Vulnerable or Higher-Risk Examples

### 1. Private Python package with public fallback

```txt
--extra-index-url https://pypi.internal.example/simple/
company-auth-lib==1.2.0
```

Risk: pip can search both the public and private indexes. If `company-auth-lib` appears on the public registry with a higher version, dependency confusion is possible unless an internal proxy or hash-pinning control prevents fallback.

Expected classification: `dependency_confusion_context = HIGH_RISK_PUBLIC_FALLBACK`

### 2. Deep dependency tree with weak transitive provenance

```yaml
direct_dependency:
name: "@scope/pkg-a"
publisher: verified
provenance: sigstore_attested
transitive_dependency:
name: "pkg-c"
depth: 6
publisher: unknown
maintainer_count: 1
last_release_age_months: 39
provenance: missing
```

Risk: the direct dependency has strong evidence, but trust degrades in a reachable transitive package.

Expected classification: `provenance_chain_propagation = DEGRADED_TRANSITIVE_TRUST`

### 3. Lockfile exists but cannot support incident bisecting

```yaml
lockfile:
file: package-lock.json
committed: false
integrity_hash_coverage: complete
build:
artifact_attestation: missing
release_notes_reference_lockfile_digest: false
```

Risk: the lockfile can make a local install reproducible today, but it cannot prove which dependency graph shipped with an older artifact.

Expected classification: `bisectability_score = WEAK`

## Benign or Lower-Risk Examples

### 1. Scoped npm package with explicit private registry routing

```ini
@company:registry=https://npm.internal.example/
registry=https://registry.npmjs.org/
```

```json
{
"packages": {
"node_modules/@company/core": {
"resolved": "https://npm.internal.example/@company/core/-/core-1.2.0.tgz",
"integrity": "sha512-..."
}
}
}
```

Risk context: the internal scope resolves only through the private registry and the lockfile confirms the source host.

Expected classification: `dependency_confusion_context = PATTERN_PRESENT_MITIGATED_BY_ROUTING`

### 2. Deep but well-provenanced dependency tree

```yaml
dependency_tree:
max_depth: 9
all_versions_pinned: true
all_lock_entries_have_integrity_hashes: true
publisher_verification_coverage: high
known_cve_count: 0
stale_or_single_maintainer_high_risk_count: 0
```

Risk context: depth alone should not be treated as high risk when lockfile, provenance, and maintainer evidence are strong.

Expected classification: `supply_chain_risk_score = LOW_TO_MEDIUM_CONTEXTUAL`

### 3. Strong lockfile bisectability

```yaml
lockfile:
file: pnpm-lock.yaml
committed: true
integrity_hash_coverage: complete
build:
provenance: slsa_l2
artifact_attestation_references_lockfile_digest: true
```

Risk context: the deployed artifact can be traced back to the exact dependency set used at build time.

Expected classification: `bisectability_score = STRONG`