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
162 changes: 118 additions & 44 deletions skills/appsec/dependency-scanning/SKILL.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
case_id: dep-scan-non-registry-benign-001
fixture_intent: "Expected to pass only because non-registry dependencies are pinned, covered by lockfiles, and reviewed as data."
expected_result: allow_with_documented_evidence
dependencies:
- package: acme-widget
source_type: git
source_host: github.com
repository: example/acme-widget
requested_ref: release-1.4.2
resolved_commit: 9f1c7a2b4d6e8f00112233445566778899aabbcc
lockfile_digest: "sha256:2df3f7d2a8b4f67a834e6c06c2a0fcd32909cc891ca03d81683f5aefc3f52b41"
install_scripts: none
- package: render-tools
source_type: direct_archive
source_host: downloads.example.invalid
requested_url: "https://downloads.example.invalid/render-tools-1.2.3.tar.gz"
resolved_digest: "sha256:fa5b8e9d8d8be7d92e8bd3ed0e85ec38a057f8afcc95c58d6b26f3e23336a614"
lockfile_matches_manifest: true
install_scripts: none
- package: local-helper
source_type: local_path
requested_path: "../vendor/local-helper"
repository_path: "vendor/local-helper"
source_review: "vendored code included in SBOM component list"
lockfile_matches_manifest: true
install_scripts: reviewed_without_execution
normalization_evidence:
pypi_declared: "Acme.Widget"
pypi_canonical: "acme-widget"
expected_review:
supply_chain_status: "Documented non-registry dependency, no immediate vulnerability finding."
retest_trigger: "Any ref, digest, path, host, lockfile, or install-script change."
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
case_id: dep-scan-spdx-vex-benign-001
fixture_intent: "Expected to pass when the scan records precise license, VEX, and reachability evidence."
expected_result: allow_with_documented_evidence
license_evidence:
package: report-exporter
version: 4.8.2
usage_scope: shipped-runtime
declared_license: "LGPL-2.1-only OR Apache-2.0"
selected_branch: "Apache-2.0"
evidence_source:
- "lockfile package metadata"
- "publisher license file"
- "approved-license policy entry"
expected_review: "Record the selected permissive branch and do not flag by the LGPL substring alone."
dev_only_evidence:
package: fixture-snapshotter
version: 1.5.0
usage_scope: dev-only
declared_license: "GPL-3.0-only WITH Autoconf-exception-3.0"
distribution_evidence: "not bundled, not linked, not copied into container image"
expected_review: "Keep the finding informational unless distribution evidence changes."
vex_reachability_evidence:
cve: CVE-2025-0002
package: xml-tokenizer
affected_version: 6.0.1
cvss: 8.8
epss_probability: 0.003
epss_percentile: 0.21
kev_listed: false
vex_status: not_affected
vex_product: "minorstep-importer 2.7.0"
vex_component: "xml-tokenizer 6.0.1"
vex_justification: "vulnerable code path is not present in the compiled production bundle"
call_graph_evidence: "parser.parseExternalEntity is not referenced by production routes"
retest_trigger: "dependency version, route exposure, or bundle target changes"
expected_priority: P3
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
case_id = "dep-scan-non-registry-vulnerable-001"
fixture_intent = "Expected to fail a scanner that trusts registry CVE output while ignoring direct sources and lockfile gaps."
expected_result = "flag"

[project]
name = "non-registry-blind-spot"
version = "0.0.0"
dependencies = [
"Acme.Widget @ git+https://github.com/example/acme-widget.git@main",
"render-tools @ https://downloads.example.invalid/render-tools-1.2.3.tar.gz",
"Local-Helper @ file://../vendor/local-helper",
]

[lockfile]
present = true
matches_manifest = false
resolved_ref_for_acme_widget = "main"
archive_digest_for_render_tools = ""
path_dependency_digest_for_local_helper = ""

[install_scripts]
root_preinstall = ""
transitive_postinstall = "scripts/collect-build-metadata.js"
script_reviewed_without_execution = false

[expected_review]
mutable_git_ref = "Flag branch or tag refs without a resolved commit SHA."
direct_archive = "Require a digest, trusted host evidence, and TLS/source provenance before trusting the archive."
path_dependency = "Record local path provenance and explain whether it enters the build artifact."
install_hook = "Review root and transitive hooks as data without executing them."
lockfile_drift = "Do not trust vulnerability or license findings until the manifest and lockfile graph are reconciled."
normalization = "Normalize Acme.Widget as acme-widget where ecosystem rules require it."
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
case_id: dep-scan-vex-downgrade-vulnerable-001
fixture_intent: "Expected to fail a scan that downgrades a CVE using incomplete VEX or reachability evidence."
expected_result: flag
finding:
cve: CVE-2025-0001
package: json-stream-bridge
version: 3.2.0
fixed_in: 3.2.4
cvss: 9.1
epss_probability: 0.42
epss_percentile: 0.97
kev_listed: true
dependency_group: production
runtime_exposure: internet-facing_api
scanner_downgrade_claim:
vex_status: not_affected
vex_product: platform-worker
vex_component: json-stream-bridge
vex_version: "3.x"
reachability_summary: "No route observed in staging smoke test"
evidence_gaps:
- "VEX product does not match the shipped service name and version."
- "Subcomponent path is missing from the SBOM relationship graph."
- "The vulnerable parser function is reachable from /api/import in production."
- "EPSS percentile is high and the CVE is KEV-listed, so downgrade requires stronger evidence."
- "No retest date or fixed-version verification is recorded."
expected_review:
priority: P0
action: "Do not downgrade. Patch or mitigate within the KEV timeline and document reachable production exposure."
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
case_id: dep-scan-spdx-scope-vulnerable-001
fixture_intent: "Expected to fail a dependency scanner that classifies licenses by substring or ignores usage scope."
expected_result: flag
review_context:
ecosystem: mixed
files_reviewed:
- package.json
- package-lock.json
- pyproject.toml
- uv.lock
lockfile_state: stale
signals:
- id: spdx_or_branch_ignored
package: report-renderer
version: 2.4.1
usage_scope: shipped-runtime
declared_license: "GPL-3.0-only OR MIT"
scanner_result: "high-risk GPL because the raw string contains GPL"
expected_review: "Parse the SPDX expression, record the selected branch, and verify whether the permissive branch is valid for this distribution."
- id: exception_collapsed_to_base_license
package: bytecode-agent
version: 0.8.0
usage_scope: build-plugin
declared_license: "GPL-2.0-only WITH Classpath-exception-2.0"
scanner_result: "high-risk GPL-2.0"
expected_review: "Evaluate the WITH exception before assigning copyleft risk."
- id: noassertion_shipped_runtime
package: media-transcoder
version: 5.1.0
usage_scope: shipped-runtime
declared_license: NOASSERTION
scanner_result: "low risk because no GPL substring was found"
expected_review: "Treat unknown or no-license runtime packages as high-risk until evidence is obtained."
- id: dev_scope_promoted_to_distribution
package: snapshot-test-runner
version: 7.0.3
usage_scope: dev-only
declared_license: "AGPL-3.0-only"
scanner_result: "production AGPL violation"
expected_review: "Confirm whether the package is shipped, linked, bundled, or network-exposed before applying runtime obligations."
- id: lockfile_scope_drift
package: report-renderer
manifest_scope: production
lockfile_scope: dev
expected_review: "Report the analyzed graph as stale or indeterminate until manifest and lockfile scopes match."
normalization_checks:
pypi_declared: "Data.Renderer"
pypi_canonical: "data-renderer"
expected_review: "Apply PEP 503 normalization before flagging typosquatting or package mismatch."