fix(cli): reject out-of-range port numbers in parsePort (#83900) (#84008)

Summary:
- The PR adds a 65,535 upper-bound check to the shared CLI `parsePort` helper, a colocated regression test, and a changelog entry for the linked port-range bug.
- Reproducibility: yes. Source inspection on current main shows `parsePort('99999')` delegates to `parseStrict ... sitive safe integer, so the return would be `99999`; I did not execute it because this review is read-only.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cli): reject out-of-range port numbers in parsePort (#83900)

Validation:
- ClawSweeper review passed for head 9ad0705c44.
- Required merge gates passed before the squash merge.

Prepared head SHA: 9ad0705c44
Review: https://github.com/openclaw/openclaw/pull/84008#issuecomment-4484883200

Co-authored-by: HCL <chenglunhu@gmail.com>
Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
This commit is contained in:
hcl 2026-05-19 19:36:12 +08:00 committed by GitHub
parent d7083bab4c
commit e2c8e7c8ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 49 additions and 1 deletions

View file

@ -70,6 +70,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- CLI: reject explicit port numbers above 65535 before they reach Gateway or Node bind paths. Fixes #83900. (#84008) Thanks @hclsys.
- Codex app-server: preserve plugin tool auth profiles when Codex owns model transport so OpenClaw dynamic tools can resolve their provider credentials. (#83603) Thanks @rubencu.
- Memory/search: scan the JS-side fallback vector path (used when the sqlite-vec index is unavailable or has a mismatched dimension) in bounded rowid batches and yield to the event loop between batches so large chunk tables can no longer pin the Node.js main thread for multi-second windows. Also keeps the SQL prepared statement rooted in a local so node:sqlite cannot finalize it mid-scan under heap pressure. Fixes #81172. Thanks @dev23xyz-oss.
- Memory Wiki: preserve fs-safe diagnostics when bridge source page writes fail for non-symlink filesystem safety reasons, so directory collisions are reported with the underlying error code. (#83776) Thanks @TurboTheTurtle.

View file

@ -0,0 +1,37 @@
import { describe, expect, it } from "vitest";
import { parsePort } from "./parse-port.js";
describe("parsePort (#83900)", () => {
it("returns null for nullish inputs", () => {
expect(parsePort(undefined)).toBeNull();
expect(parsePort(null)).toBeNull();
});
it("returns null for zero and negative values (already enforced)", () => {
expect(parsePort(0)).toBeNull();
expect(parsePort(-1)).toBeNull();
expect(parsePort("0")).toBeNull();
});
it("accepts valid TCP port values", () => {
expect(parsePort(1)).toBe(1);
expect(parsePort(8080)).toBe(8080);
expect(parsePort("3000")).toBe(3000);
expect(parsePort(65535)).toBe(65535);
});
it("rejects port numbers above 65535 (regression for #83900)", () => {
expect(parsePort(65536)).toBeNull();
expect(parsePort(99999)).toBeNull();
expect(parsePort("100000")).toBeNull();
// Largest 16-bit value is the inclusive boundary.
expect(parsePort(65535)).toBe(65535);
});
it("rejects non-integer and non-finite inputs", () => {
expect(parsePort(1.5)).toBeNull();
expect(parsePort(Number.NaN)).toBeNull();
expect(parsePort(Number.POSITIVE_INFINITY)).toBeNull();
expect(parsePort("abc")).toBeNull();
});
});

View file

@ -1,8 +1,18 @@
import { parseStrictPositiveInteger } from "../../infra/parse-finite-number.js";
// TCP/UDP ports are 16-bit, so 65535 is the max. `parseStrictPositiveInteger`
// only enforces positivity, so values like 99999 were returned as-is and
// reached gateway-cli / node-cli bind paths; the OS then surfaced the error
// instead of the CLI rejecting it cleanly at parse time. See #83900.
const MAX_TCP_PORT = 65_535;
export function parsePort(raw: unknown): number | null {
if (raw === undefined || raw === null) {
return null;
}
return parseStrictPositiveInteger(raw) ?? null;
const parsed = parseStrictPositiveInteger(raw);
if (parsed === undefined || parsed > MAX_TCP_PORT) {
return null;
}
return parsed;
}