fix: report the post-redirect URL instead of silently mislabeling it#109
Closed
dmchaledev wants to merge 1 commit into
Closed
fix: report the post-redirect URL instead of silently mislabeling it#109dmchaledev wants to merge 1 commit into
dmchaledev wants to merge 1 commit into
Conversation
…loses #93) fetchHeaders always graded the final response but analyze() labeled the report with the pre-redirect input URL, so a report could describe host B while claiming to describe host A. Add fetchHeadersWithMeta to capture res.url and surface it as report.finalUrl whenever it differs, with a CLI note when a scan was redirected. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpbiJ21pAx17d217g7m6Tj
Contributor
Author
|
Closing: this PR's Generated by Claude Code |
dmchaledev
added a commit
that referenced
this pull request
Jul 19, 2026
…114) Reimplements #109 on top of #99's SSRF-hardened fetch loop (redirect: 'manual' with per-hop private-IP validation) instead of the old redirect: 'follow' call #109 assumed, which would have silently reintroduced the SSRF-via-redirect gap. - src/fetch.ts: fetchHeadersWithMeta(url, options) returns {headers, finalUrl}, reusing the existing hop loop; fetchHeaders is now a thin wrapper. - src/types.ts: optional finalUrl on SecurityHeaderReport (additive). - src/index.ts: analyze() sets report.finalUrl when it differs from the input. - src/cli.ts: prints "Redirected to: <url>" and includes finalUrl in --json. - Updated test/cli.test.ts's fetch.js mock (previously exported fetchHeaders, which index.ts no longer calls) to export fetchHeadersWithMeta instead. Closes #93. Co-authored-by: claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fetchHeadersalways fetches withredirect: 'follow'and grades whatever response comes back, butanalyze()labeled the report with the pre-redirect input URL, never the URL the headers actually came from.http://→https://, apex →www, marketing domain → app domain, staging → login page, etc.) would silently get a report that saysurl: "https://example.com"while every finding actually describes a different host — with no field anywhere to tell you that happened.security-headers https://staging.example.com || exit 1grading the wrong host with no indication) and multi-tenant/ASM scanning (misattributing a customer's grade to the wrong hostname).Changes
src/fetch.ts: addfetchHeadersWithMeta(url, options)which capturesres.url(the fetch spec guarantees this is the final URL after redirects) alongside the header map.fetchHeadersis now a thin wrapper around it, so its existing signature/behavior is unchanged.src/types.ts: add optionalfinalUrl?: stringtoSecurityHeaderReport— additive, non-breaking.src/index.ts:analyze()setsreport.finalUrlwhenever it differs from the requested URL.src/cli.ts: printsRedirected to: <url>when a scan followed a redirect; included as-is in--jsonoutput since it's just a report field.README.md: documents the newfinalUrlfield.test/fetch.test.ts(new) coversfetchHeadersWithMeta/fetchHeadersagainst a mocked globalfetch;test/analyzer.test.tscoversanalyze()setting/omittingfinalUrl.Test plan
npm run typechecknpm test(90 passing)npm run build🤖 Generated with Claude Code
https://claude.ai/code/session_01JpbiJ21pAx17d217g7m6Tj
Generated by Claude Code