T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/bazi_chart.py:112
- Finding
- Unbounded Year-Range Input Can Cause Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bazi_chart.py`, lines 112–116; related argument definition at line 224 **Vulnerability Type**: Uncontrolled resource consumption **Risk Level**: Medium ### Vulnerable Code ```python start_year = from_year or datetime.now().year liunian = [] for yy in range(start_year, start_year + max(1, years)): # Calculate the annual stem and branch using the midpoint of the Gregorian year ysolar = Solar.fromYmdHms(yy, 6, 30, 12, 0, 0) yl = ysolar.getLunar().getEightChar().getYear() liunian.append({'year': yy, 'ganzhi': yl}) ``` The corresponding command-line argument has no upper bound: ```python ap.add_argument('--years', type=int, default=10, help='Generate annual results; default: 10 years') ``` ### Technical Analysis The user-controlled `--years` argument determines the number of iterations performed by the annual-results loop. Although `max(1, years)` prevents zero or negative iteration counts, the code does not impose an upper limit. Every iteration performs calendar conversion through `lunar_python` and appends a new dictionary to the in-memory `liunian` list. A sufficiently large value can therefore cause excessive CPU use and continuous memory growth. Processing ends only when the loop completes, the dependency rejects an unsupported year, or the process exhausts available resources. The issue is reachable through the documented command-line interface. Its practical severity depends on how the script is deployed: impact is limited for trusted local use but becomes more significant if an Agent, API, queue worker, or other automated service passes untrusted values to the script. ### Attack Path 1. An attacker or untrusted caller gains control over the `--years` argument. 2. The caller invokes the script with an excessive value, for example: ```bash python scripts/bazi_chart.py \ --date 1989-10-17 \ --time 12:00 \ --gender male \ --years 1000000000 ``` ...[truncated 1283 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Enforce a strict application-level limit in `build()` so callers cannot bypass command-line validation: ```python MAX_YEARS = 100 if not 1 <= years <= MAX_YEARS: raise ValueError(f"years must be between 1 and {MAX_YEARS}") ``` 2. Add an `argparse` validator to reject invalid values before processing: ```python def bounded_year_count(value: str) -> int: count = int(value) if not 1 <= count <= 100: raise argparse.ArgumentTypeError("years must be between 1 and 100") return count ap.add_argument( '--years', type=bounded_year_count, default=10, help='Number of annual results to generate, from 1 to 100' ) ``` 3. Validate `--from-year` and the computed ending year against the calendar range supported by `lunar_python`. 4. If invoked by a network-facing or multi-user service, also enforce request timeouts, per-user rate limits, memory limits, and CPU quotas. These controls should supplement rather than replace input validation. 5. Add regression tests covering zero, negative, maximum permitted, above-maximum, and unsupported year-range inputs. ]]>
