Repository navigation
Conversation
view() printed ORGANIZER and ATTENDEE values verbatim, so an .ics file previewed with the icalendar command could send terminal escape sequences. Escape C0 controls other than tab and newline, DEL and C1 controls as \xNN in the returned text. AI: Claude Opus 5.5 (claude-opus-5-5) Prompt: Find a security bug in icalendar, write a minimal fix with a regression test, and draft the pull request. Output: The model found that the cli prints vCalAddress values raw, reproduced it with an .ics containing ESC/OSC sequences, and wrote this commit, which I reviewed.
|
Thanks for the pull request, @alhudz! A maintainer will review it shortly. |
|
One or more PR-quality checks did not pass. Review the PR Quality Checks summary in the workflow run for the failed checks and their details, then make any necessary updates. Checklist items may remain unchecked while work is in progress. Please tick each item as you complete it. If you used AI assistance, follow the project's Responsible AI use policy and provide the required disclosures. |
angatha
left a comment
There was a problem hiding this comment.
Looks good. Tests pick just some values but I think we should test that all bad ones are always escape to prevent regressions.
| output += cli.view(event) + "\n\n" | ||
| assert output == PROPER_OUTPUT | ||
|
|
||
| def test_control_characters_are_escaped(self): |
There was a problem hiding this comment.
Can you change this (or add anew test) with parameterrs for each "bad" character so we can detect if one of thouse is no longer escaped?
There was a problem hiding this comment.
Added test_each_control_character_is_escaped, parametrised over every C0 control except tab and newline, DEL and every C1 control (63 cases, ids are the hex code). It sets ORGANIZER as a plain string so \r reaches view() too, since the parser treats it as a line break. All 63 fail on main and pass with the fix. I kept the original test as an end-to-end check through from_ical.
There was a problem hiding this comment.
Whats the reason for excluding thouse three?
There was a problem hiding this comment.
Only two are excluded, tab (0x09) and newline (0x0a). DEL (0x7f) is in the list and escaped, my earlier wording was ambiguous there.
_escape_control_chars() runs over the whole formatted block, and view() uses \n for its own layout (one attendee per line, indented description lines), so escaping it would put everything on one line. DESCRIPTION also keeps real newlines, which test_output_is_proper checks. Neither of the two can move the cursor back or start an escape sequence, so they can't rewrite what is already on screen. \r is escaped for that reason: it returns to the start of the line and the rest overwrites it.
|
Hm. Personally, I think the CLI is really old - it can be improved. I wonder if anyone uses it. It is for people to look at files. It should probably use parse. |
|
Agreed, it could do with some work. If you mean |
Linked issue
Description
icalendar.cli.view()putsORGANIZERandATTENDEEvalues into the printed summary as they are.vTextstrips C0 controls fromSUMMARY,LOCATION,COMMENTandDESCRIPTION, butvCalAddresskeeps them, andvTextkeeps C1 controls such asU+009B. So runningicalendar invite.icson a received file lets the file drive the terminal.Repro:
printf 'BEGIN:VEVENT\r\nORGANIZER:mailto:boss\x1b]0;pwned\x07\x1b[1A\x1b[2K@example.com\r\nDTSTART:20250101T120000Z\r\nEND:VEVENT\r\n' > esc.ics && icalendar esc.icsExpected: the escape bytes are shown as text.
Actual: the terminal title changes to
pwnedand the line above the organiser is erased.Fix:
view()now escapes C0 controls other than tab and newline, DEL and C1 controls as\xNN, sostdoutand--outputfiles both get plain text. Tab and newline stay as they are, so multi-line descriptions look the same.Checklist
Additional information
test_control_characters_are_escapedfails onmainand passes with this change. Full suite: 21437 passed.ruff checkandruff format --checkare clean.