Skip to content

Commit 033fbe6

Browse files
committed
fix(analyzer): rely on runner for SC7 example filtering to close executable 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 #224. Signed-off-by: CharmingGroot <ohyes9711@gmail.com>
1 parent 2b15280 commit 033fbe6

2 files changed

Lines changed: 21 additions & 7 deletions

File tree

src/skillspector/nodes/analyzers/static_patterns_supply_chain.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
from skillspector.state import AnalyzerNodeResponse, SkillspectorState
3838

3939
from . import static_runner
40-
from .common import get_context, get_line_number, is_code_example
40+
from .common import get_context, get_line_number
4141
from .osv_client import ECOSYSTEM_NPM, ECOSYSTEM_PYPI, VulnResult, query_batch, was_osv_reachable
4242
from .pattern_defaults import PatternCategory
4343
from .static_runner import analyzer_finding_to_finding
@@ -585,13 +585,12 @@ def ctx(start: int) -> str:
585585
matched_text=match.group(0)[:200],
586586
)
587587
)
588-
# SC7: untrusted container image. Filtered through is_code_example() because
589-
# these flags appear in SKILL.md docs and "never do this" warnings.
588+
# SC7: untrusted container image. Example handling is left to the shared
589+
# runner, which suppresses matches in non-executable docs and only
590+
# downweights (does not skip) executables — so an in-code "example" marker
591+
# cannot bypass the rule in a shell script.
590592
for pattern, confidence in SC7_PATTERNS:
591593
for match in re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE):
592-
context_text = ctx(match.start())
593-
if is_code_example(context_text):
594-
continue
595594
line_num = get_line_number(content, match.start())
596595
findings.append(
597596
AnalyzerFinding(
@@ -601,7 +600,7 @@ def ctx(start: int) -> str:
601600
location=loc(line_num),
602601
confidence=confidence,
603602
tags=tag,
604-
context=context_text,
603+
context=ctx(match.start()),
605604
matched_text=match.group(0)[:200],
606605
)
607606
)

tests/nodes/analyzers/test_static_patterns.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,21 @@ def test_sc7_benign_pull_no_finding(self):
239239
findings = static_runner.run_static_patterns(state, [supply_chain_module])
240240
assert not any(f.rule_id == "SC7" for f in findings)
241241

242+
def test_sc7_example_marker_in_executable_still_fires(self):
243+
"""An 'example' marker near a bypass in an executable .sh must NOT suppress SC7.
244+
245+
Example filtering belongs to the runner, which only downweights (does not
246+
skip) executables — so a nearby '# for example' cannot be used to evade SC7.
247+
"""
248+
state = {
249+
"components": ["setup.sh"],
250+
"file_cache": {
251+
"setup.sh": "# for example\ndocker pull --disable-content-trust registry.io/x",
252+
},
253+
}
254+
findings = static_runner.run_static_patterns(state, [supply_chain_module])
255+
assert any(f.rule_id == "SC7" for f in findings)
256+
242257

243258
class TestRunStaticPatternsAgentSnoopingAdditional:
244259
"""run_static_patterns with agent_snooping: AS1, AS2, AS3."""

0 commit comments

Comments
 (0)