Skip to content

util.stripVTControlCharacters() fails to strip OSC 8 hyperlinks whose URI contains characters like "(" #64313

Description

@sindresorhus

Version

v22.22.3 (also reproduces on main)

Platform

Any (logic bug in a bundled regex, not platform-specific)

Subsystem

util

What steps will reproduce the bug?

import {stripVTControlCharacters} from 'node:util';

// OSC 8 hyperlink whose URI contains `(`, a character RFC 3986 allows unencoded.
const link = '\u001B]8;;https://example.com/(foo\u0007label\u001B]8;;\u0007';

console.log(stripVTControlCharacters(link));

How often does it reproduce? Is there a required condition?

Always, whenever an OSC 8 hyperlink URI contains one of: !, $, ', (, ), *, +, ,, [, ].

What is the expected behavior? Why is that the expected behavior?

The visible label with all escape sequences removed:

label

What do you see instead?

The hyperlink is not stripped and most of the URI (plus the BEL terminator) leaks into the output. The returned string is:

'ttps://example.com/(foo\u0007label'

Additional information

stripVTControlCharacters() uses a bundled copy of chalk/ansi-regex in lib/internal/util/inspect.js, pinned to ansi-regex f338e18 (v6.1.0). That version matches OSC parameter/URI bytes with the restricted class [-a-zA-Z\d/#&.:=?%@~_], which omits ten characters RFC 3986 permits unencoded in a URI: !, $, ', (, ), *, +, ,, [, ]. When the URI contains any of them, the OSC branch never reaches the string terminator, so the sequence is left largely intact.

ansi-regex fixed this in v6.2.0 (72bc570) by matching OSC sequences generically as ESC ] … ST (non-greedy up to the first string terminator) instead of enumerating allowed URI bytes. Syncing the bundled regex to ansi-regex >=6.2.0 resolves it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions