24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
# File 'lib/rules/cache_poisoning.rb', line 24
def check(workflow)
findings = []
has_pr_trigger = pr_triggered?(workflow)
workflow.uses_actions.each do |action|
uses = action[:uses]
next unless CACHE_ACTIONS.any? { |ca| uses&.start_with?(ca) }
step = action[:step]
key_value = step.dig("with", "key")
next unless key_value
DANGEROUS_KEY_PATTERNS.each do |pattern|
if key_value.match?(pattern)
findings << finding(workflow,
line: action[:line] || 0,
code: "key: #{key_value}",
message: "Cache key contains fork-controllable reference — risk of cache poisoning",
fix: "Use hashFiles() for cache keys, not branch refs. Consider prefixing fork PR cache keys."
)
break
end
end
if has_pr_trigger && key_value.match?(GITHUB_REF_PATTERN)
findings << finding(workflow,
line: action[:line] || 0,
code: "key: #{key_value}",
message: "Cache key uses github.ref on pull_request trigger — resolves to mutable PR merge ref",
fix: "Use hashFiles() for cache keys, not branch refs. Consider prefixing fork PR cache keys."
)
end
end
findings
end
|