Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
24b2f0b
fix(security): bound static regex matching with runtime deadlines
yashrajp22 Oct 5, 2026
e4d98f2
fix(security): specialize timed regex categories for ASCII input
yashrajp22 Oct 5, 2026
c1bc167
fix(security): charge regex budget only while advancing matches
yashrajp22 Oct 5, 2026
6bc8c39
test: reuse scaled windows for public surface separator coverage
yashrajp22 Oct 5, 2026
e305809
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
91b6d16
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
34b906d
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
db6a983
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
76d0654
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
d218360
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
032b15b
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
7a5a1ce
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
a98479b
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
154cbb3
fix(analyzers): compact Unicode matching and preserve search limits
yashrajp22 Oct 5, 2026
24bed2f
fix(analyzers): skip curl backtracking when required flags are absent
yashrajp22 Oct 5, 2026
e5eec2f
style(analyzers): format curl suffix prefilter
yashrajp22 Oct 5, 2026
36a289c
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
d96dbab
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
b8b3ad8
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
d722477
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
c532a79
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
0105b66
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 5, 2026
b6efd31
fix(analyzers): scan command patterns linearly across pipe segments
yashrajp22 Oct 6, 2026
4c5976c
fix(analyzers): cover download-then-execute command searches
yashrajp22 Oct 6, 2026
d86d841
test(analyzers): finalize command matcher regression coverage
yashrajp22 Oct 6, 2026
96a9af8
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
e53fee8
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
55211ff
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
96aed2c
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
3f9d0e5
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
669f8f3
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
58d2dbb
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
d80d356
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
802e740
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
33ba730
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
d0d4dad
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
6937d17
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 6, 2026
d379b6e
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 7, 2026
4a1e2c4
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 7, 2026
1565283
fix(analyzer): cover remaining code-pattern deadline paths
yashrajp22 Oct 7, 2026
87ec67a
test(analyzer): retain timeout ledger coverage for code rules
yashrajp22 Oct 7, 2026
3e59edd
style: format timed matching regression controls
yashrajp22 Oct 7, 2026
2f896e2
test(analyzer): exercise repeated permission anchors
yashrajp22 Oct 7, 2026
42330d1
Merge main and preserve bounded analyzer routing
yashrajp22 Oct 9, 2026
2e9436c
fix(analyzer): share paragraph budgets and retain routed merge behavior
yashrajp22 Oct 9, 2026
df9f7b0
fix(analyzer): retain native Unicode backreference semantics safely
yashrajp22 Oct 9, 2026
22ad582
fix(analyzer): reject unsupported case-folded backreferences
yashrajp22 Oct 9, 2026
1d340cb
fix(analyzer): report truncated call tails and bound schema whitespace
yashrajp22 Oct 9, 2026
670d77c
style: format anti-refusal regression cases
yashrajp22 Oct 9, 2026
607cd83
test(analyzer): retain one AST index for dense shell-flag matches
yashrajp22 Oct 9, 2026
5e0af36
style: preserve first-party import grouping
yashrajp22 Oct 9, 2026
f391201
fix(analyzer): preserve variable-flow offsets after leading blank lines
yashrajp22 Oct 9, 2026
cc39071
fix(analyzer): preserve bounded parser span metrics in ledger
yashrajp22 Oct 9, 2026
0977e39
fix(analyzer): respect ASCII mode in boundary shortcuts
yashrajp22 Oct 9, 2026
dbff21c
style: format ASCII boundary parity assertion
yashrajp22 Oct 9, 2026
f776f8a
style: format boundary shortcut predicate
yashrajp22 Oct 9, 2026
810db1b
Merge current analyzer semantics while preserving bounded matching
yashrajp22 Oct 9, 2026
739e7dc
style: format analyzer merge resolution
yashrajp22 Oct 9, 2026
2aef0f6
fix(analyzer): remove replaced command pattern from timed registry
yashrajp22 Oct 9, 2026
7960173
test(analyzer): make selected-rule timeout routing deterministic
yashrajp22 Oct 9, 2026
6b2c8c9
Merge remote-tracking branch 'origin/main' into yashraj/fix-static-pa…
yashrajp22 Oct 9, 2026
4492841
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 9, 2026
19140a6
Merge branch 'main' into yashraj/fix-static-pattern-regex-timeouts
github-actions[bot] Oct 9, 2026
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
31 changes: 31 additions & 0 deletions docs/ANALYSIS_RESOURCE_BOUNDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ removes the rejected partial checkout.
| Static findings | 10,000 | One artifact |
| Static findings | 10,000 | One analyzer |
| Static-analysis time | 300 seconds | One artifact, within the workflow deadline |
| Timed static-pattern matching CPU | 0.25 seconds | One rule per content window, shared across paragraphs, within the artifact and workflow deadlines |
| YARA rule-directory entries | 10,000 | Built-in and optional directories combined |
| YARA rule files | 1,024 | One rule load |
| YARA rule source bytes | 1 MiB | One rule file |
Expand Down Expand Up @@ -333,6 +334,36 @@ default. Set `SKILLSPECTOR_MAX_STATIC_ANALYSIS_SECONDS_PER_ARTIFACT` to a positi
finite number of seconds to change that allowance. Invalid, zero, negative,
infinite, or NaN values log a warning and retain the 300-second default.

The shared matcher has a fixed 0.25-second matching CPU limit per rule and content window.
Paragraph-matched rules share this allowance across all their paragraphs.
Raising the artifact allowance does not raise this limit. It covers routed rules
in prompt injection, tool misuse, data exfiltration, supply chain, agent snooping,
excessive agency, memory poisoning, and rogue agents. Through paragraph matching,
it also covers prose rules in harmful content, system prompt leakage, output
handling, anti-refusal, privilege escalation, and SSRF. Output-handling and
privilege-escalation code patterns also use the timed matcher. Other code rules (SSRF endpoint/request patterns,
harmful-content substance names, and deserialization DS1–DS4) and helper-specific
searches remain outside it. The anti-refusal schema-field helper uses a linear
whitespace prefix so its benign-context check cannot backtrack quadratically.

Audited command/option patterns use a linear, command-segment search that preserves
unbounded command spans and the original greedy matches. Memory poisoning's
2–20-character repetition rule uses Python's native engine: failed candidates
examine at most 20 copies, and successful candidates consume the repeated run.
The variable shell-flag rule also retains Python’s native backreference semantics.
It checks assignment headers separately and bounds each candidate call-argument
tail to 4,096 characters, with the same accumulated matching CPU allowance. A
potential match extending beyond that span reports `static_parse_limit`.
The repetition rule is bounded by the 256,000-character inspection window and the
artifact deadline, rather than the slower engine's per-search timer.

Matching CPU accounting excludes caller work and other threads. The interruptible
engine itself measures process CPU, however, so native work in competing threads
can interrupt a search early. Retrying discards progress and can still exhaust the
matching allowance under sustained contention. If a search expires, its ledger
event keeps the observed time and limit, and that analyzer records partial coverage
for the artifact while retaining findings already produced.

## Configuring the dependency-source deadline

Dependency-source redirection analysis allows up to 5 seconds by default. Set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in AS1_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = get_line_number(content, match.start())
Expand All @@ -176,7 +176,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in AS2_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = get_line_number(content, match.start())
Expand All @@ -196,7 +196,9 @@ def ctx(start: int) -> str:

for pattern, confidence in AS3_PATTERNS:
is_prose = (pattern, confidence) in AS3_PROSE_PATTERNS
matches = static_runner.iter_paragraph_matches if is_prose else re.finditer
matches = (
static_runner.iter_paragraph_matches if is_prose else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
if is_prose and is_directly_prohibited(content, match.start(), match.end()):
continue
Expand Down
16 changes: 8 additions & 8 deletions src/skillspector/nodes/analyzers/static_patterns_anti_refusal.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
from skillspector.state import AnalyzerNodeResponse, SkillspectorState

from . import static_runner
from .common import SourceLocationIndex, get_context, get_line_number, is_code_example
from .common import SourceLocationIndex, get_context_from_lines, is_code_example
from .pattern_defaults import PatternCategory

logger = get_logger(__name__)
Expand Down Expand Up @@ -188,14 +188,14 @@
)
_BENIGN_AR_SCHEMA_FIELD_PATTERN = re.compile(
r"""
^\s*(?:\[\])?\s+(?:field|key|property|array|list|entry)\b
^(?:\s*\[\])?\s+(?:field|key|property|array|list|entry)\b
|
^\s*(?:\[\])?\s+(?:in|of)\s+(?:the\s+)?(?:json(?:\s+output)?|output|response)\s+schema\b
^(?:\s*\[\])?\s+(?:in|of)\s+(?:the\s+)?(?:json(?:\s+output)?|output|response)\s+schema\b
|
^\s*(?:\[\])?\s+(?:in|of)\s+(?:the\s+)?(?:warnings?|disclaimers?|caveats?)\b(?:\[\])?\s+
^(?:\s*\[\])?\s+(?:in|of)\s+(?:the\s+)?(?:warnings?|disclaimers?|caveats?)\b(?:\[\])?\s+
(?:field|key|property|array|list|entry)\b
|
^\s*(?:\[\])?\s+in\s+(?:the\s+)?errors\[\]\s+array\b
^(?:\s*\[\])?\s+in\s+(?:the\s+)?errors\[\]\s+array\b
""",
re.IGNORECASE | re.VERBOSE,
)
Expand Down Expand Up @@ -566,6 +566,7 @@ def analyze(
"""Analyze content for anti-refusal statements (AR1-AR3)."""
findings: list[AnalyzerFinding] = []
locations = SourceLocationIndex(content, file_path)
lines = content.splitlines()
tag = [PatternCategory.ANTI_REFUSAL.value]
python_comments = (
_PythonComments(content, check_runtime or _no_runtime_check)
Expand All @@ -584,11 +585,10 @@ def analyze(
and _is_descriptive_python_comment(python_comments, match)
):
continue
lines = content.splitlines()
line_num = get_line_number(content, match.start())
line_num, column = locations.line_and_column(match.start())
Comment thread
yashrajp22 marked this conversation as resolved.
match_line = lines[line_num - 1] if lines else content
previous_line = lines[line_num - 2] if line_num > 1 else None
context = get_context(content, match.start(), context_lines=3)
context = get_context_from_lines(lines, line_num, window=3, column=column)
security_review_context = bool(
_MODE_ENABLED_RE.fullmatch(match.group(0))
and _SECURITY_REVIEW_CONTEXT_RE.search(context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in E1_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
Comment thread
yashrajp22 marked this conversation as resolved.
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = get_line_number(content, match.start())
Expand Down Expand Up @@ -337,7 +337,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in E2_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = get_line_number(content, match.start())
Expand All @@ -358,7 +358,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in E3_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = get_line_number(content, match.start())
Expand Down Expand Up @@ -395,7 +395,9 @@ def ctx(start: int) -> str:
)
# E5: cloud-storage exfiltration. Example filtering is delegated to the runner.
for pattern, confidence in E5_PATTERNS:
for match in re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE):
for match in static_runner.iter_pattern_matches(
pattern, content, re.IGNORECASE | re.MULTILINE
):
line_num = get_line_number(content, match.start())
findings.append(
AnalyzerFinding(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in EA1_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = get_line_number(content, match.start())
Expand All @@ -445,7 +445,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in EA2_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
if (pattern, confidence) in EA2_PROSE_PATTERNS and (
Expand Down Expand Up @@ -495,7 +495,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in EA4_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = get_line_number(content, match.start())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@
]

# MP2: Context Window Stuffing — filling context to displace content
_BOUNDED_REPETITION_PATTERN = r"(.{2,20}?)\1{20,}"
MP2_CONTENT_PATTERNS = [
(r"(.{2,20}?)\1{20,}", 0.8),
(_BOUNDED_REPETITION_PATTERN, 0.8),
]
MP2_PROSE_PATTERNS = [
(
Expand Down Expand Up @@ -541,10 +542,16 @@ def ctx(start: int) -> str:
)
)
for pattern, confidence in MP2_PATTERNS:
# For each start there are only 19 candidate lengths. A failed candidate
# checks at most 20 copies; a success consumes its entire repeated run.
# There is no trailing condition to force it to backtrack over that run.
# Keep this linear, window-bounded rule on Python's faster native engine.
matches = (
static_runner.iter_paragraph_matches
re.finditer
if pattern == _BOUNDED_REPETITION_PATTERN
else static_runner.iter_paragraph_matches
if (pattern, confidence) in MP2_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
Comment thread
yashrajp22 marked this conversation as resolved.
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
span = match.group(0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in OH1_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
if pattern == _EXEC_OUTPUT_PATTERN and _is_javascript_regexp_literal_exec(
Expand Down Expand Up @@ -690,7 +690,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in OH3_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = get_line_number(content, match.start())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ def context_at(offset: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in PE1_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = line_number(match.start())
Expand All @@ -1022,7 +1022,7 @@ def context_at(offset: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in PE2_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = line_number(match.start())
Expand All @@ -1047,7 +1047,7 @@ def context_at(offset: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in PE3_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
if _is_bare_credential_store_noun(
Expand Down Expand Up @@ -1162,7 +1162,9 @@ def context_at(offset: int) -> str:
# that match multiple patterns (e.g. DockerClient(base_url=".../docker.sock")).
pe4_best: dict[int, AnalyzerFinding] = {}
for pattern, confidence in PE4_PATTERNS:
for match in re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE):
for match in static_runner.iter_pattern_matches(
pattern, content, re.IGNORECASE | re.MULTILINE
):
line_num = line_number(match.start())
context = context_at(match.start())
finding_tags = list(tag)
Expand All @@ -1186,7 +1188,9 @@ def context_at(offset: int) -> str:
# often matches multiple flags (e.g. --privileged + --cap-add=SYS_ADMIN).
pe5_best: dict[int, AnalyzerFinding] = {}
for pattern, confidence in PE5_PATTERNS:
for match in re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE):
for match in static_runner.iter_pattern_matches(
pattern, content, re.IGNORECASE | re.MULTILINE
):
line_num = line_number(match.start())
context = context_at(match.start())
finding_tags = list(tag)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def _p2_pattern_matches(
check_runtime()
compiled = re.compile(pattern, re.IGNORECASE | re.DOTALL)
if pattern not in _SINGLE_CHARACTER_P2_PATTERNS:
for match in compiled.finditer(content):
for match in static_runner.iter_pattern_matches(compiled, content):
if check_runtime is not None:
check_runtime()
yield match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def ctx(start: int) -> str:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in RA1_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = bisect_right(line_starts, match.start())
Expand Down Expand Up @@ -323,7 +323,9 @@ def ctx(start: int) -> str:
)
for pattern, confidence in RA2_PATTERNS:
is_prose = (pattern, confidence) in RA2_PROSE_PATTERNS
matches = static_runner.iter_paragraph_matches if is_prose else re.finditer
matches = (
static_runner.iter_paragraph_matches if is_prose else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
if is_prose and is_directly_prohibited(content, match.start(), match.end()):
continue
Expand Down
16 changes: 11 additions & 5 deletions src/skillspector/nodes/analyzers/static_patterns_supply_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1975,7 +1975,9 @@ def _iter_sc2_shell_matches(
covered = 0
for start, end in command_ranges:
if end is None:
yield from compiled.finditer(content, max(start, covered))
yield from static_runner.iter_pattern_matches(
compiled, content, start=max(start, covered)
)
return
if start < covered:
continue
Expand Down Expand Up @@ -2017,7 +2019,7 @@ def line_number(start: int) -> int:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in SC1_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.MULTILINE):
line_num = line_number(match.start())
Expand All @@ -2042,7 +2044,9 @@ def line_number(start: int) -> int:
pattern, content, re.IGNORECASE | re.MULTILINE
)
else:
matches = re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE)
matches = static_runner.iter_pattern_matches(
pattern, content, re.IGNORECASE | re.MULTILINE
)
for match in matches:
line_num = line_number(match.start())
mt = match.group(0)
Expand Down Expand Up @@ -2132,7 +2136,7 @@ def line_number(start: int) -> int:
matches = (
static_runner.iter_paragraph_matches
if (pattern, confidence) in SC3_PROSE_PATTERNS
else re.finditer
else static_runner.iter_pattern_matches
)
for match in matches(pattern, content, re.IGNORECASE | re.MULTILINE):
line_num = line_number(match.start())
Expand All @@ -2151,7 +2155,9 @@ def line_number(start: int) -> int:
)
# SC7: untrusted container image. Example filtering is delegated to the runner.
for pattern, confidence in SC7_PATTERNS:
for match in re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE):
for match in static_runner.iter_pattern_matches(
pattern, content, re.IGNORECASE | re.MULTILINE
):
line_num = line_number(match.start())
findings.append(
AnalyzerFinding(
Expand Down
Loading