Skip to content

Conversation

kingthorin
Copy link
Member

Overview

The External Redirect scan rules has been updated to account for potential false positives involving JavaScript comments.

@psiinon
Copy link
Member

psiinon commented Aug 20, 2025

Logo
Checkmarx One – Scan Summary & Details2532e07b-50c5-43c2-aff1-ddae52a20685

Great job! No new security vulnerabilities introduced in this pull request


Communicate with Checkmarx by submitting a PR comment with @Checkmarx followed by one of the supported commands. Learn about the supported commands here.

@kingthorin kingthorin force-pushed the redir-wavsep-fps branch 3 times, most recently from 10ed03c to 6b120f2 Compare August 23, 2025 15:41
@kingthorin kingthorin marked this pull request as ready for review August 24, 2025 22:21
@kingthorin kingthorin requested a review from Copilot August 25, 2025 02:32
Copilot

This comment was marked as outdated.

Copilot

This comment was marked as outdated.

@kingthorin kingthorin force-pushed the redir-wavsep-fps branch 6 times, most recently from 3c91fd7 to 436c2b7 Compare August 26, 2025 21:13
@kingthorin
Copy link
Member Author

Deconflicted

@@ -531,6 +531,68 @@ void shouldReportRedirectWithJsLocationMethods(String jsMethod) throws Exception
assertThat(alertsRaised.get(0).getEvidence().startsWith(HttpHeader.HTTP), equalTo(true));
}

private static Stream<Arguments> provideCommentStrings() {
Copy link
Member

Choose a reason for hiding this comment

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

  • This should have malformed escapes and comments.
  • Better run the test coverage, no escapes are actually being tested (the escape char needs to be escaped).
  • All comments should lead to an alert if it wasn't for the fix, if you revert the scan rule changes and run the test only two cases fail, they all should fail.

Copy link
Member Author

Choose a reason for hiding this comment

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

For your first bullet can you be more specific? Or provide some examples?

Copy link
Member

Choose a reason for hiding this comment

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

e.g. \u A, \x B, /* not closed ….

Copy link
Member Author

Choose a reason for hiding this comment

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

Got all that, I think.

Copy link
Member

@thc202 thc202 Sep 2, 2025

Choose a reason for hiding this comment

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

  • Missing cases for \u{HHH} (1 to 6 digits long) and octal, unicode and hex broken half way through, from looking at the latest push.
  • The hex escape is just two chars (the other ones are not really needed).
  • There should also be a case for single quote strings and template literals (containing comment chars to make sure those are properly accepted).

Copy link
Member

Choose a reason for hiding this comment

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

\xHH not \xHHHH the latter is just one hex escape followed by two chars (case w/ malformed (mid) hex escape is incorrect, to be middle it would be \xH H).

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, tweaked.

Copy link
Member

@thc202 thc202 Sep 4, 2025

Choose a reason for hiding this comment

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

The parsing logic keeps changing everyday which is fine but that means the tests should be updated to cover the new cases, there are still conditions not covered, which should to make sure there are no bugs.

Copy link
Member Author

@kingthorin kingthorin Sep 4, 2025

Choose a reason for hiding this comment

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

It was changing often to cover cases you kept thinking of, which is great because I wasn't seeing/catching them, and I thought I was extending the test inputs to cover things but maybe not sufficiently.

Just added a few for nested comments 🤷‍♂️

Copy link
Member Author

Choose a reason for hiding this comment

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

Found, added, and updated code for more edge cases.

@kingthorin kingthorin force-pushed the redir-wavsep-fps branch 5 times, most recently from 0d6d8cb to 6c9a24c Compare September 2, 2025 15:39
@kingthorin kingthorin requested a review from Copilot September 3, 2025 18:05
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

The External Redirect scan rule has been updated to reduce false positives by excluding JavaScript code that appears within comments from triggering redirect vulnerability alerts.

  • Added JavaScript comment parsing logic to filter out commented code before pattern matching
  • Enhanced test coverage with comprehensive comment scenarios including various escape sequences and edge cases
  • Updated changelog to document the false positive improvement

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
ExternalRedirectScanRule.java Added JavaScript comment extraction logic and state machine parser to filter out commented code
ExternalRedirectScanRuleUnitTest.java Added comprehensive test cases covering various JavaScript comment scenarios and edge cases
CHANGELOG.md Documented the false positive fix for JavaScript comments

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Matcher matcher = pattern.matcher(value);
// We know the payload is present.
// Ensure the value has something we're likely interested in before dealing with comments
if (JS_PRE_CHECKS.stream().noneMatch(chk -> StringUtils.containsIgnoreCase(value, chk))) {
Copy link
Member

Choose a reason for hiding this comment

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

I'd suggest keeping the previous check (even if that means matching twice), instead of adding additional checks which must be kept in sync with the patterns.

Copy link
Member Author

Choose a reason for hiding this comment

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

You mean the domain check? Then drop the simple JS checks?

Copy link
Member

Choose a reason for hiding this comment

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

The pattern check. Yes, the JS_PRE_CHECKS.

Copy link
Member Author

Choose a reason for hiding this comment

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

So do matcher.find both before and after?

Copy link
Member

Choose a reason for hiding this comment

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

Right.

Copy link
Member

Choose a reason for hiding this comment

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

Worth doing the StringUtils.startsWithIgnoreCase as well, better extract a method.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done & done

@kingthorin
Copy link
Member Author

Got all those I believe

@kingthorin kingthorin force-pushed the redir-wavsep-fps branch 4 times, most recently from 9b9d595 to d6c8475 Compare September 4, 2025 15:42
Set<String> comments =
ExternalRedirectScanRule.extractJsComments(BODY_TEMPLATE.formatted(content));
// Then
assertThat(comments, hasSize(1));
Copy link
Member

Choose a reason for hiding this comment

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

The numbers are not enough, it should be checked the content as well otherwise we don't know if the boundaries are properly detected.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've adjusted this. Indeed some of the results are perhaps not as we'd wish. I've added comments to the situations I feel are debatable .

Comment on lines +732 to +734
// What do we really want in this case?
"console.log(\"example\"); /* console.log('comment'); ",
"/* console.log('comment'); \n</script></head><body><H1>Redirect</H1></body></html>"),
Copy link
Member Author

Choose a reason for hiding this comment

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

For this rule I think we only deal with JS inside HTML, so capturing to the closing script tag is probably reasonable.

In the future we could have a boolean that indicates if the end of script tag is used, or some other behavior to pure JS files.

Comment on lines +851 to +856
Arguments.of(
"Template expression with inner comment",
// Is this the behavior we want? I believe this should either be both or
// just trailing. The current result seems wrong to me.
"console.log(`outer ${ /* inner comment */ 42 }`); // trailing comment",
"/* inner comment */"),
Copy link
Member Author

Choose a reason for hiding this comment

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

I propose that this should simply capture the trailing comment.

Comment on lines +865 to +870
// This results in a zero comments situation. I believe that's likely fine as
// the unterminated literal should be an app failure on it's own
// Arguments.of(
// "Unterminated template literal",
// "console.log(`unterminated template ${1+1} //
// comment not terminated", "?"),
Copy link
Member Author

Choose a reason for hiding this comment

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

Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants