T09 · Insecure Skill Coding Practices
- Location
scripts/obs_lifecycle_analyzer.py:477- Finding
Lifecycle rule update confirmation relies on a stale preview
- Content
View full analysis
Vulnerability Details
File Location:
scripts/obs_lifecycle_analyzer.py, lines 332–354 and 477–515
Vulnerability Type: Confirmation-gate bypass through time-of-check/time-of-use inconsistency
Risk Level: HighVulnerable Code
python def preview(bucket: str, prefix: str = "", rule_id: str = "", days: int = 0, action: str = "", limit: int = 1000) -> dict: cfg = get_lifecycle_config(bucket) rules = cfg.get("Rules") or [] objects = list_objects(bucket, prefix, limit) now = datetime.now(timezone.utc) results = [] total = 0 total_size = 0 scanned = [o for o in objects if o["key"].startswith(prefix)] if rule_id and days == 0 and not action: rule = next((r for r in rules if r.get("ID") == rule_id), None) if not rule: sys.exit(f"ERROR: rule '{rule_id}' not found in bucket {bucket}") effective = _rule_effective_prefix(rule) useprefix = effective input_objects = [o for o in objects if o["key"].startswith(useprefix)] for kind, d, cls, date_iso in _rule_actions(rule): affected = [o for o in input_objects if _action_reached(kind, d, date_iso, o["last_modified"], now)]python if prefix: rule["Prefix"] = prefix if rule.get("Filter"): rule["Filter"]["Prefix"] = prefix has_exp = bool(_has_meaningful_expiration(rule)) has_trans = bool(rule.get("Transitions")) if days > 0: if action == "expire": # Explicit expiration update — only touch Expiration. exp = rule.get("Expiration") if exp: exp["Days"] = days else: rule["Expiration"] = {"Days": days} elif action == "transition": # Explicit transition update — only touch Transitions. trans = rule.get("Transitions") if trans: trans[0]["Days"] = days else: rule["Transitions"] = [{"Days": days, "StorageClass": storage_class or "COLD"}] elif has_trans a ...[truncated 4244 chars]- Remediation
View remediation
Remediation Suggestions
- Refactor preview generation so it accepts and evaluates the locally modified rule object instead of refetching the currently deployed rule.
- Calculate the preview from the exact configuration object that will be passed to
_put_config(). - Display the complete pending rule or configuration alongside the affected-object summary before requesting confirmation.
- Bind confirmation to a digest of the pending configuration and verify that the same digest is applied after confirmation.
- Refetch the remote configuration immediately before writing and reject the update if it changed after the initial read, preventing concurrent updates from invalidating the reviewed merge.
- Add regression tests covering:
- Prefix expansion and narrowing.
- Shorter and longer expiration periods.
- Expiration-to-transition and transition-to-expiration changes.
- Storage-class changes.
- Rules containing both expiration and transition actions.
- Concurrent remote configuration changes.
- Retain the interactive confirmation gate by default and ensure
--applyis used only by a caller that has independently presented and confirmed the exact pending configuration.
