Skip to content

fix: validate --timeout CLI arg to prevent silent NaN abort#61

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

fix: validate --timeout CLI arg to prevent silent NaN abort#61
dmchaledev wants to merge 1 commit into
mainfrom
claude/nice-mendel-Vvwx7

Conversation

@dmchaledev
Copy link
Copy Markdown
Contributor

Summary

  • Bug: passing a non-numeric value to --timeout (e.g. --timeout notanumber) caused parseInt to return NaN. Because NaN is not null/undefined, the ?? 10000 fallback in fetch.ts was bypassed. setTimeout then received NaN, which Node.js/browsers treat as 0 — aborting every request immediately with an opaque AbortError.
  • Secondary bug: URL detection used a !== String(timeoutMs) to exclude the timeout value from URL candidates. When timeoutMs is NaN, String(NaN) === 'NaN', not the actual raw string (e.g. 'notanumber'), so the invalid input could be misidentified as the URL.
  • Also handled: --timeout with no following value (last arg, or immediately before another flag) now emits a clear error instead of silently ignoring the flag.

Changes (src/cli.ts)

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

After:
  const timeoutIdx = args.indexOf('--timeout');
  const rawTimeout = timeoutIdx !== -1 ? args[timeoutIdx + 1] : undefined;
  // Fail fast if --timeout has no value or its value is another flag
  if (timeoutIdx !== -1 && (rawTimeout === undefined || rawTimeout.startsWith('--'))) { exit(1) }
  const timeoutMs = rawTimeout !== undefined ? parseInt(rawTimeout, 10) : undefined;
  // Fail fast if value is not a positive integer
  if (timeoutMs !== undefined && (isNaN(timeoutMs) || timeoutMs <= 0)) { exit(1) }
  // Use raw string for exclusion, not String(NaN)
  const url = args.find(a => !a.startsWith('--') && a !== rawTimeout);

User-visible behaviour after fix

Command Before After
security-headers https://example.com --timeout notanumber Request aborted immediately (NaN → 0 ms timeout) Error: --timeout value must be a positive integer in milliseconds (e.g. --timeout 5000), got: 'notanumber' + exit 1
security-headers https://example.com --timeout Silently ignored Error: --timeout requires a value in milliseconds (e.g. --timeout 5000) + exit 1
security-headers https://example.com --timeout --json Silently ignored Same clear error
security-headers https://example.com --timeout 5000 Works Still works

Test plan

  • npm run typecheck — passes (no TypeScript errors)
  • npm test — all 82 existing tests pass
  • Manual smoke-test: node dist/cli.js https://example.com --timeout notanumber → clear error message, exit 1
  • Manual smoke-test: node dist/cli.js https://example.com --timeout 5000 → normal report

https://claude.ai/code/session_01V8MbP8UKNDFzXh4oMew2C2


Generated by Claude Code

Previously, passing a non-numeric value like --timeout notanumber caused
parseInt to return NaN. Since NaN is not null/undefined, the ?? fallback in
fetch.ts was skipped, and setTimeout received NaN (treated as 0 by browsers
and Node), aborting every request immediately with an opaque AbortError.

The fix:
- Errors immediately with a clear message if --timeout is missing its value
  or if the value parses to NaN or a non-positive number.
- Uses the raw string (not String(NaN)) to exclude the timeout value from
  the URL-candidate scan, fixing a secondary bug where the timeout string
  could have been picked up as the URL.

https://claude.ai/code/session_01V8MbP8UKNDFzXh4oMew2C2
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