T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/cache-hardening-audit.sh:95
- Finding
- Multiline YAML Values Bypass Cache Security Checks<![CDATA[ ## Vulnerability Details **File Location**: `scripts/cache-hardening-audit.sh`, lines 95–98, 139–160, and 190–211 **Vulnerability Type**: Incomplete parsing of YAML block scalar values **Risk Level**: Medium ### Vulnerable Code ```python restore_key_re = re.compile(r"^\s*-\s*(.+?)\s*$") path_re = re.compile(r"^\s*path\s*:\s*(.+?)\s*(?:#.*)?$") with_re = re.compile(r"^\s*with\s*:\s*$") ``` ```python key_value = None restore_keys = [] path_values = [] base_indent = len(line) - len(line.lstrip(' ')) saw_with_block = False for follow_idx in range(idx + 1, len(lines) + 1): follow = lines[follow_idx - 1] stripped = follow.strip() if not stripped: continue indent = len(follow) - len(follow.lstrip(' ')) if indent <= base_indent and (stripped.startswith('- ') or stripped.startswith('uses:') or stripped.startswith('name:') or re.match(r'^\w', stripped)): break if with_re.match(follow): saw_with_block = True continue key_match = key_re.match(follow) if key_match: key_value = key_match.group(1).strip().strip('"\'') continue path_match = path_re.match(follow) if path_match: path_values.append(path_match.group(1).strip().strip('"\'')) continue if saw_with_block and stripped.startswith('- '): rk = restore_key_re.match(follow) if rk: restore_keys.append(rk.group(1).strip().strip('"\'')) ``` ```python broad_restore = [rk for rk in restore_keys if rk.endswith('-') and rk.count('-') <= 2] if broad_restore: step_weight += 1 step_issues.append({ 'code': 'broad_restore_keys', 'message': 'restore-keys appears broad and may over-share cache entries across contexts.', 'lines': [idx], 'weight': 1, 'details': broad_restore[:5], }) sensitive_hits = [] for value in path_values: lowered = value.lower() for token in sensitive_path_tokens: if token in lowered: ...[truncated 3442 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the line-oriented regular-expression parser with a safe YAML parser and inspect the resulting workflow structure. 2. Parse each job's `steps` collection and identify cache actions by the normalized `uses` value. 3. Read `with.path`, `with.key`, and `with.restore-keys` as structured YAML values, supporting both scalar and sequence representations. 4. Split multiline `path` and `restore-keys` scalar values into individual normalized entries before applying security checks. 5. Support literal and folded block scalar forms, including `|`, `|-`, `|+`, `>`, `>-`, and `>+`. 6. If a YAML parser cannot be introduced, implement indentation-aware block scalar handling that tracks the parent field and consumes all subordinate lines. This is less reliable than structured YAML parsing and should be treated as a temporary mitigation. 7. Add regression tests for: - Literal and folded multiline paths. - Sensitive paths including `.ssh`, `.aws`, `.npmrc`, `.pypirc`, and `.git`. - Multiline broad `restore-keys` prefixes. - Quoted and unquoted scalar values. - Multiple cache steps in one job. - Comments, blank lines, chomping indicators, expressions, and YAML sequences. 8. Fail safely or emit a prominent parse warning when workflow syntax cannot be interpreted reliably, rather than silently treating the workflow as safe. ]]>
