Skip to content

Conversation

@adriangohjw
Copy link
Contributor

Problem

What problem are you trying to solve? What issue does this close?

Closes https://linear.app/ogp/issue/ISOM-2008/vapt-insufficient-referrer-validation-bypasses-transition-page

Solution

How did you solve the problem?

Improvements:

  • use built-in URL function to check instead of startsWith
  • extract into private method for readability
  • add tests

Tests

What tests should be run to confirm functionality?

  • refer to Linear ticket for steps to reproduce

@adriangohjw adriangohjw self-assigned this Jul 21, 2025
@adriangohjw adriangohjw added the enhancement New feature or request label Jul 21, 2025
@linear
Copy link

linear bot commented Jul 21, 2025

@adriangohjw
Copy link
Contributor Author

bugbot run

@adriangohjw adriangohjw requested review from a team July 21, 2025 23:23
cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@adriangohjw adriangohjw marked this pull request as draft July 21, 2025 23:36
@adriangohjw
Copy link
Contributor Author

Bug: Trusted Referrer Tests Expect Incorrect Redirect

The RedirectService.test.ts file contains incorrect expectations for trusted referrer scenarios. Tests for referrers from the same origin as ogUrl (e.g., exact match, with path, or with query parameters) currently expect RedirectType.TransitionPage. However, the RedirectService's logic dictates RedirectType.Direct for these cases, as a trusted referrer should bypass the transition page.

fixed tests in 29b40c8

@adriangohjw adriangohjw marked this pull request as ready for review July 22, 2025 00:11
cursor[bot]

This comment was marked as outdated.

@adriangohjw
Copy link
Contributor Author

Bug: Malformed URL in Security Test

The test "should NOT allow transition page bypass for domain containing ogUrl" constructs a malformed referrer URL. The template literal https://staging.${ogUrl}.malicious.com results in https://staging.https://go.gov.sg.malicious.com because ogUrl already includes https://, creating a double protocol. While the test passes (as invalid URLs are correctly treated as untrusted), it does not test the intended scenario of a malicious domain containing the trusted domain name. The URL should be https://staging.go.gov.sg.malicious.com.

fixed in 9206094

}

const isFromTrustedPage = referrer.startsWith(ogUrl)
const isFromTrustedPage = RedirectService.isFromTrustedPage(referrer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: should use this instead of RedirectService

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually im not super familiar with the framework, but i referenced this from an existing code

if (RedirectService.isValidShortUrl(rawShortUrl)) {
throw new NotFoundError('Invalid Url')
}

private static isValidShortUrl(shortUrl: string): boolean {
return !shortUrl || !/^[a-zA-Z0-9-]+$/.test(shortUrl)
}

curious - what's the issue for this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah oops sorry was reviewing on mobile, so didn't see the static part. Doing RedirectService.isFromTrustedPage is ok since isFromTrustedPage is a static function. If otherwise then should use this.

)
})

describe('referrer validation', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can name it after the function instead? Easier to identify and debug

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated in 36b91b0 👍

Comment on lines 54 to 59
redirectService = new RedirectService(
mockUrlRepository as unknown as UrlRepositoryInterface,
mockCrawlerCheckService as unknown as CrawlerCheckService,
mockCookieArrayReducerService as unknown as CookieArrayReducerService,
mockLinkStatisticsService as unknown as LinkStatisticsService,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: I think this init can be outside of the beforeEach and describe, might help in making tests run a bit faster

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated in 1684f26 👍

}

const isFromTrustedPage = referrer.startsWith(ogUrl)
const isFromTrustedPage = RedirectService.isFromTrustedPage(referrer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah oops sorry was reviewing on mobile, so didn't see the static part. Doing RedirectService.isFromTrustedPage is ok since isFromTrustedPage is a static function. If otherwise then should use this.

@adriangohjw adriangohjw merged commit c83ebf4 into develop Jul 23, 2025
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants