Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fix(input): bail OSC code accumulation past 22 to prevent overflow
The numeric OSC code loop accumulated digits with no cap, so a long
digit run (e.g. ESC ] 9999...) would overflow the int accumulator.
Since 22 is the only code parse_osc accepts and the accumulator only
grows, bail with PARSE_ERR as soon as it passes 22.

Addresses review feedback from @dreyfus92 on #101.
  • Loading branch information
natemoo-re committed Aug 21, 2026
commit 637b95437089cf3ba664840036eb2d07d445e088
5 changes: 5 additions & 0 deletions src/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,11 @@ static int parse_osc(struct InputState *st, struct InputEvent *ev) {
if (code == -1)
code = 0;
code = code * 10 + (st->buf[i] - '0');
/* 22 is the only accepted code; the accumulator only grows as digits
* arrive, so once it passes 22 no valid completion exists. Bail here so a
* long digit run can never overflow `code`. */
if (code > 22)
return PARSE_ERR;
i++;
Comment on lines +630 to +640

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the loop accumulates digits with no cap before the code != 22. feed it ESC ] 99999999999... and code overflows int. simplest guard is to clamp or bail inside the loop, e.g. break out once code > 22 (or some small ceilling) since the only code you accept is 22 anyway anything is already a PARSE_ERR.

}
if (i >= st->len)
Expand Down
9 changes: 9 additions & 0 deletions test/input.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,15 @@ describe("input", () => {
});
});

it("rejects an unbounded digit run without overflowing", () => {
// A long run of digits must not overflow the code accumulator; anything
// that grows past 22 can never match, so it is dropped as an error.
let result = input.scan(str("\x1b]" + "9".repeat(64) + ";x\x1b\\"));
expect(
result.events.some((e) => e.type === "pointershape"),
).toBe(false);
});

it("parses a reply interleaved with other input", () => {
let result = input.scan(str("a\x1b]22;default\x1b\\b"));
expect(result.events.length).toBe(3);
Expand Down
Loading