T09 · Insecure Skill Coding Practices
- Location
scripts/generate_ics.py:35- Finding
Unescaped User Input Allows ICS Calendar Content Injection
- Content
View full analysis
Vulnerability Details
File Location:
scripts/generate_ics.py, lines 35–44; attacker-controlled values are constructed at lines 75–83
Vulnerability Type: ICS property and event injection
Risk Level: MediumVulnerable Code
python for event in events: start_str = event['start'].strftime('%Y%m%dT%H%M%S{tz_offset}') end_str = event['end'].strftime('%Y%m%dT%H%M%S{tz_offset}') uid = event['uid'].replace(' ', '_') ics_content += f"""BEGIN:VEVENT UID:{uid}@clawhub.dev DTSTAMP:{datetime.utcnow().strftime('%Y%m%dT%H%M%SZ')} DTSTART:{start_str} DTEND:{end_str} SUMMARY:{event['summary']} DESCRIPTION:{event.get('description', '')} END:VEVENT """The affected values are built directly from the input project JSON:
python summary = f"{proj['name']}: {m['name']} ({m['hours']}h @ $150/hr)" desc = f"Cumulative: {cum_hours + m['hours']}h. Init fee $500 separate." events.append({ 'uid': f"{proj['name']}-{m['name']}", 'start': e_start, 'end': e_end, 'summary': summary, 'description': desc })Technical Analysis
The project name and milestone names are read from a user-supplied JSON document and inserted directly into
UIDandSUMMARYproperties. Replacing spaces in the UID does not neutralize carriage returns, line feeds, backslashes, commas, or semicolons.Under RFC 5545, a newline terminates the current content line. Consequently, an input containing an escaped JSON newline becomes a real newline after
json.load()and can introduce additional ICS properties or calendar components. Text values also require escaping of backslashes, commas, semicolons, and line breaks.For example, a malicious project name could contain content conceptually equivalent to:
json { "name": "Trusted Project\nATTENDEE:mailto:victim@example.com\nDESCRIPTION:Injected content", "start": "2026-04-01T09:00:00-06:00", "milestones": [ ...[truncated 1604 chars]- Remediation
View remediation
Remediation Suggestions
-
Apply RFC 5545 text escaping before inserting any user-controlled value:
- Escape
\as\\. - Escape commas as
\,. - Escape semicolons as
\;. - Encode line breaks as literal
\nsequences rather than physical content-line boundaries. - Reject remaining carriage returns, line feeds, NUL bytes, and other control characters.
- Escape
-
Generate opaque UIDs independently of user input, such as with
uuid.uuid4(). Do not derive structural identifiers directly from project or milestone names. -
Validate the complete JSON schema before generating output:
- Require
nameand milestone names to be strings. - Set reasonable length limits.
- Require finite, non-negative numeric hour values within an expected maximum.
- Require a valid timezone-aware start timestamp.
- Reject unexpected object structures and control characters.
- Require
-
Use a maintained iCalendar library that correctly serializes properties, escapes text, folds long lines, and handles timezone data.
-
Add regression tests using project and milestone names containing CR, LF, backslashes, commas, semicolons,
BEGIN:VEVENT, andEND:VEVENT. Verify that each remains inert text in the parsed output and cannot create extra properties or events. -
Parse the generated ICS in security tests and assert that its event count and property structure exactly match the validated input.
-
