@nonbot/cli 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/lib/payload-validator.js +18 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @nonbot/cli changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.1 (2026-09-09) — SECURITY
|
|
4
|
+
|
|
5
|
+
- **Hardens the tmux theme validator; upgrade if you run `nonbot daemon`.**
|
|
6
|
+
`isSafeTmuxConf` guards a server-supplied cosmetic theme before the daemon
|
|
7
|
+
writes it to disk and hands it to `tmux source-file`, which EXECUTES it. It
|
|
8
|
+
allowlisted the tmux *directive* (`set` / `setw` / `set-option` /
|
|
9
|
+
`set-window-option`) and denylisted three option names. tmux stores HOOKS as
|
|
10
|
+
options, and `man tmux` is explicit that `set-hook` and `set-option` are
|
|
11
|
+
equivalent for them — so a theme line naming a hook used an allowlisted
|
|
12
|
+
directive, named an option the denylist did not cover, and contained none of
|
|
13
|
+
the patterns the validator screens for (`#(`, `$(`, a backtick, a backslash, a
|
|
14
|
+
`;`). It passed every check, and tmux ran the hook's command on the next
|
|
15
|
+
matching pane event.
|
|
16
|
+
|
|
17
|
+
A denylist of option names cannot be complete here: it would have to enumerate
|
|
18
|
+
every hook tmux has now and every one it adds later. The option NAME is now
|
|
19
|
+
ALLOWLISTED instead — presentational suffixes (`-style`, `-format`, `-bg`,
|
|
20
|
+
`-fg`, `-attr`, `-colour`, `-color`, `-length`) plus a short explicit set for
|
|
21
|
+
the cosmetic options that have no such suffix — which refuses every hook by
|
|
22
|
+
construction. `lock-command`, `copy-command` and `editor` joined the forbidden
|
|
23
|
+
set alongside `default-command`, `default-shell` and `command-alias`.
|
|
24
|
+
|
|
25
|
+
Themes produced by the normal generator are unaffected. +20 tests
|
|
26
|
+
(`tests/tmux-theme-allowlist.test.ts`) covering real generated output and 13
|
|
27
|
+
rejected payloads.
|
|
28
|
+
|
|
3
29
|
## 0.10.0 (2026-09-04)
|
|
4
30
|
|
|
5
31
|
- At-exit transcript for fast-exit runs (memory C32, 2026-09-04): the daemon keeps a rolling
|
|
@@ -147,7 +147,22 @@ const TMUX_SAFE_DIRECTIVES = new Set([
|
|
|
147
147
|
]);
|
|
148
148
|
const TMUX_FORBIDDEN_OPTIONS = new Set([
|
|
149
149
|
'default-command', 'default-shell', 'command-alias',
|
|
150
|
+
'lock-command', 'copy-command', 'editor',
|
|
150
151
|
]);
|
|
152
|
+
const TMUX_SAFE_OPTION_SUFFIXES = [
|
|
153
|
+
'-style', '-format', '-bg', '-fg', '-attr', '-colour', '-color', '-length',
|
|
154
|
+
];
|
|
155
|
+
const TMUX_SAFE_OPTION_NAMES = new Set([
|
|
156
|
+
'status', 'status-position', 'status-justify', 'status-interval',
|
|
157
|
+
'window-status-separator', 'pane-border-status', 'pane-border-indicators',
|
|
158
|
+
]);
|
|
159
|
+
function isSafeTmuxOptionName(name) {
|
|
160
|
+
if (TMUX_FORBIDDEN_OPTIONS.has(name))
|
|
161
|
+
return false;
|
|
162
|
+
if (TMUX_SAFE_OPTION_NAMES.has(name))
|
|
163
|
+
return true;
|
|
164
|
+
return TMUX_SAFE_OPTION_SUFFIXES.some((suffix) => name.endsWith(suffix));
|
|
165
|
+
}
|
|
151
166
|
export function isSafeTmuxConf(conf) {
|
|
152
167
|
for (const rawLine of conf.split(/\r?\n/)) {
|
|
153
168
|
const line = rawLine.trim();
|
|
@@ -170,6 +185,9 @@ export function isSafeTmuxConf(conf) {
|
|
|
170
185
|
if (TMUX_FORBIDDEN_OPTIONS.has(tok))
|
|
171
186
|
return false;
|
|
172
187
|
}
|
|
188
|
+
const optionName = tokens.slice(1).find((t) => !t.startsWith('-'));
|
|
189
|
+
if (!optionName || !isSafeTmuxOptionName(optionName))
|
|
190
|
+
return false;
|
|
173
191
|
}
|
|
174
192
|
}
|
|
175
193
|
return true;
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.10.
|
|
1
|
+
export const VERSION = '0.10.1';
|
package/package.json
CHANGED