Skip to content

feat(analyzer): detect untrusted container image pull as SC7#224

Open
CharmingGroot wants to merge 2 commits into
NVIDIA:mainfrom
CharmingGroot:feat/sc7-untrusted-container-image
Open

feat(analyzer): detect untrusted container image pull as SC7#224
CharmingGroot wants to merge 2 commits into
NVIDIA:mainfrom
CharmingGroot:feat/sc7-untrusted-container-image

Conversation

@CharmingGroot

Copy link
Copy Markdown
Contributor

Summary

The supply_chain analyzer (SC1–SC6) covers package dependencies (PyPI/npm) but has no detection for the container-image supply chain. A skill that pulls images with verification turned off — --disable-content-trust, DOCKER_CONTENT_TRUST=0, --insecure-registry — accepts tampered or unverified images yet scored 9/100 SAFE (#223). This adds SC7, the image-layer counterpart of SC1 (unpinned) / SC6 (typosquatting).

Changes

static_patterns_supply_chain.py gains SC7_PATTERNS (three image-trust bypass flags) and an SC7 pass filtered through the shared is_code_example() helper. pattern_defaults.py registers the SC7 explanation, category, message, and remediation alongside SC1–SC6.

Before / After

A "fast image loader" skill that sets DOCKER_CONTENT_TRUST=0 and pulls with --disable-content-trust / --insecure-registry:

  • Before: 9/100 SAFE — only the unrelated --tls-verify=false line is caught (as a generic TM3 verify=False); the image-trust bypass is invisible
  • After: 57/100 HIGH, SC7 ×3 on the content-trust and insecure-registry lines

With the LLM layer (Qwen3.6-35B-A3B-FP8 via vLLM) the same skill scores 78/HIGH (SDI-1: "disables Docker Content Trust, TLS verification …"), so --no-llm / air-gapped deployments were the exposed surface this closes.

Design Decisions

Decision Rationale
Category = supply_chain (not new) A container image is a supply-chain artifact; SC7 is the image-layer version of SC1/SC6. No new category needed.
--tls-verify=false excluded TM3's existing verify=False pattern already catches it. SC7 targets only the image-specific bypasses TM3 cannot see (--disable-content-trust, DOCKER_CONTENT_TRUST=0, --insecure-registry) — avoids duplicate findings on the same line.
Severity HIGH, confidence 0.8–0.85 Disabling verification is dangerous regardless of registry. A normal docker pull nginx:1.25 does not fire.

Testing

5 new tests: detection of --disable-content-trust, DOCKER_CONTENT_TRUST=0, and --insecure-registry; a documentation-example exclusion (is_code_example); and a benign-pull negative. make format and make lint pass; uv run pytest -m "not integration and not provider" reports 1003 passed, 0 failed.

Closes #223

supply_chain (SC1-SC6) covers package dependencies but not the container-image supply chain. A skill pulling images with verification disabled (--disable-content-trust, DOCKER_CONTENT_TRUST=0, --insecure-registry) accepts tampered images but scored 9/SAFE (NVIDIA#223). Add SC7_PATTERNS to the supply_chain analyzer (is_code_example filter) with pattern_defaults entries and 5 tests. --tls-verify=false is excluded since TM3's verify=False already covers it.

Signed-off-by: CharmingGroot <ohyes9711@gmail.com>

@rng1995 rng1995 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SC7 patterns and metadata are otherwise well integrated, but the new module-level example filter lets executable code evade the rule with a nearby marker. Please rely on the runner's file-type-aware handling, or only suppress non-executable content, and add an executable-file evasion regression.

for pattern, confidence in SC7_PATTERNS:
for match in re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE):
context_text = ctx(match.start())
if is_code_example(context_text):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: this unconditional skip creates an attacker-controlled bypass in executable files. is_code_example() returns true for any nearby 'for example', code fence, and similar marker, so a shell script with '# for example' within three lines of 'docker pull --disable-content-trust ...' produces no SC7 finding. The shared runner already filters examples in non-executable docs and only downweights them in executable files. Remove or scope this early continue and add an executable evasion regression.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — my mistake. The runner already applies is_code_example (filtering non-executable docs and only downweighting executables), so calling it again in the SC7 loop with an unconditional continue is redundant and opens exactly the executable-file bypass you flagged: a # for example within a few lines of docker pull --disable-content-trust suppresses the finding entirely.

Fix incoming: drop the is_code_example call from SC7 and rely on the runner's file-type-aware handling, plus a regression test asserting a content-trust bypass in a .sh still fires with an example marker nearby.

CharmingGroot added a commit to CharmingGroot/SkillSpector that referenced this pull request Jun 30, 2026
…utable bypass

SC7 called is_code_example() with an unconditional continue, letting a nearby example marker (e.g. a '# for example' comment a few lines from a content-trust bypass) suppress the rule in executable files. The shared runner already filters examples in non-executable docs and only downweights executables, so the analyzer-level call was redundant and created an attacker-controlled bypass. Drop it and rely on the runner's file-type-aware handling; add an executable-file evasion regression test. Addresses review feedback on NVIDIA#224.

Signed-off-by: CharmingGroot <ohyes9711@gmail.com>
CharmingGroot added a commit to CharmingGroot/SkillSpector that referenced this pull request Jun 30, 2026
E5 (NVIDIA#218) and TM4 (NVIDIA#220) called is_code_example() with an unconditional continue, letting a nearby example marker (e.g. "# for example") suppress findings in executable files. The shared runner already filters examples in non-executable docs and only downweights executables, so the analyzer-level call was redundant and created an attacker-controlled bypass — the same issue fixed for SC7 in NVIDIA#224. Remove it from both analyzers; replace TM4's analyze-level doc-exclusion test with an executable-evasion test and add the equivalent E5 regression.

Signed-off-by: CharmingGroot <ohyes9711@gmail.com>
…utable bypass

SC7 called is_code_example() with an unconditional continue, letting a nearby example marker (e.g. a '# for example' comment a few lines from a content-trust bypass) suppress the rule in executable files. The shared runner already filters examples in non-executable docs and only downweights executables, so the analyzer-level call was redundant and created an attacker-controlled bypass. Drop it and rely on the runner's file-type-aware handling; add an executable-file evasion regression test. Addresses review feedback on NVIDIA#224.

Signed-off-by: CharmingGroot <ohyes9711@gmail.com>
@CharmingGroot CharmingGroot force-pushed the feat/sc7-untrusted-container-image branch from 033fbe6 to 9526734 Compare June 30, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants