Skip to content

fix(cli): validate --timeout value instead of silently coercing to NaN#100

Open
dmchaledev wants to merge 1 commit into
mainfrom
claude/nice-mendel-wucbl9
Open

fix(cli): validate --timeout value instead of silently coercing to NaN#100
dmchaledev wants to merge 1 commit into
mainfrom
claude/nice-mendel-wucbl9

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Problem

cli.ts parsed --timeout with parseInt(...) and passed the result straight through with no validation:

const timeoutArg = args.find((a, i) => a === '--timeout' && args[i + 1]);
const timeoutMs = timeoutArg ? parseInt(args[args.indexOf('--timeout') + 1], 10) : undefined;

Any non-numeric or missing value (a typo, or --timeout accidentally placed before the URL) parses to NaN. NaN is not null/undefined, so fetch.ts's options?.timeoutMs ?? 10000 passes it straight to setTimeout. Node treats a NaN delay as ~1ms, so the AbortController fires almost instantly:

$ security-headers https://example.com --timeout abc
Error: This operation was aborted

$ security-headers --timeout https://example.com   # flag/URL order mistake
Error: This operation was aborted

Both reproduced against a real network call before this fix (see commit for verification). For a tool whose flagship use case is a CI gate (security-headers $URL || echo "Gate failed"), a mistyped flag silently produces a generic abort error rather than a clear message pointing at the actual mistake — easy to misdiagnose as a network or target problem.

Fix

  • Extracted argument parsing into a pure parseArgs() in src/cli-args.ts (previously inlined in main(), which has network + process.exit side effects and is awkward to unit test).
  • --timeout is now validated: non-numeric or non-positive values produce a clear Error: --timeout requires a positive number of milliseconds (got ...) and exit 1, instead of a silently-broken near-instant timeout.
  • URL detection now excludes the --timeout value by argument position, not by comparing every arg against String(timeoutMs) — the old approach was a coincidental hack that happened to work only because a URL is unlikely to literally equal "NaN".
  • Added test/cli-args.test.ts covering valid/invalid/missing --timeout, flag/URL ordering, and --help/--version detection.

Test plan

  • npm run typecheck passes
  • npm test passes (94 tests, including 9 new ones)
  • npm run build passes
  • Manually verified before the fix: --timeout abc and --timeout <url> (flag before URL) both aborted almost instantly with a misleading error
  • Manually verified after the fix: both now exit 1 with a clear, actionable message; --timeout 3000 and a plain URL with no flags still work; a real https://example.com scan still runs end-to-end and grades correctly

Generated by Claude Code

An invalid or missing --timeout value (e.g. `--timeout abc`, or
`--timeout` misplaced before the URL) parsed to NaN and was passed
straight through to fetchHeaders. setTimeout(..., NaN) fires in ~1ms in
Node, so the fetch aborted almost immediately with a cryptic "This
operation was aborted" instead of a clear usage error — misleading for
a tool whose main use case is a CI gate.

Extract argument parsing into a pure parseArgs() in src/cli-args.ts so
it's unit-testable without invoking main()'s network/process.exit side
effects, and reject non-positive/non-numeric --timeout values with an
actionable error message.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants