diff --git a/rules/standard/security/SecurityHelper.go b/rules/standard/security/SecurityHelper.go
index a7041ca..3fc2d1b 100644
--- a/rules/standard/security/SecurityHelper.go
+++ b/rules/standard/security/SecurityHelper.go
@@ -38,7 +38,11 @@ func findVulnerableLinesBetweenTags(fileToScan files.File, ruleId string, extraV
if hasOpeningScriptOrStyleTagFound {
// Search for closing script or style tag
if closeScriptStyleTagRegexp.MatchString(line.Text) {
- hasOpeningScriptOrStyleTagFound = false
+ closeTagEnd := closeScriptStyleTagRegexp.FindStringIndex(line.Text)[1]
+ openTagMatch := openScriptStyleTagRegexp.FindStringIndex(line.Text[closeTagEnd:])
+ if openTagMatch == nil {
+ hasOpeningScriptOrStyleTagFound = false
+ }
}
isInsideScriptOrStyleTag = true
@@ -49,8 +53,12 @@ func findVulnerableLinesBetweenTags(fileToScan files.File, ruleId string, extraV
//Search for closing script or style tag at same line
isScriptOrStyleClosingTag := closeScriptStyleTagRegexp.MatchString(line.Text)
if isScriptOrStyleClosingTag {
- columnRange[0] = openScriptStyleTagRegexp.FindStringIndex(line.Text)[1]
- columnRange[1] = closeScriptStyleTagRegexp.FindStringIndex(line.Text)[0]
+ openTagEnd := openScriptStyleTagRegexp.FindStringIndex(line.Text)[1]
+ closeTagMatch := closeScriptStyleTagRegexp.FindStringIndex(line.Text[openTagEnd:])
+ if closeTagMatch != nil {
+ columnRange[0] = openTagEnd
+ columnRange[1] = openTagEnd + closeTagMatch[0]
+ }
} else if !isScriptOrStyleClosingTag && !selfCloseScriptStyleTagRegexp.MatchString(line.Text) {
hasOpeningScriptOrStyleTagFound = true
}
@@ -60,7 +68,7 @@ func findVulnerableLinesBetweenTags(fileToScan files.File, ruleId string, extraV
//IF line is between script or style tag
if isInsideScriptOrStyleTag {
//If column range is present
- if columnRange[0] != columnRange[1] {
+ if columnRange[0] < columnRange[1] {
vulnerableLines = append(vulnerableLines, rules.Occurrence{
LineNumber: line.LineNumber,
LineContent: line.Text,
diff --git a/rules/standard/security/SecurityHelper_test.go b/rules/standard/security/SecurityHelper_test.go
index a112b5c..fde35ff 100644
--- a/rules/standard/security/SecurityHelper_test.go
+++ b/rules/standard/security/SecurityHelper_test.go
@@ -84,3 +84,105 @@ func TestFindVulnerableLinesWithExtraVulnerableTags(t *testing.T) {
t.Errorf("%s Actual: %+v, Expected: %+v", "Occurrences list should be equal!", actualResult, expectedResult)
}
}
+
+// TestFindVulnerableLinesOpenAndCloseTagOnSameLine verifies that the column range
+// is correctly computed relative to the open tag end when both
+// appear on the same line.
+func TestFindVulnerableLinesOpenAndCloseTagOnSameLine(t *testing.T) {
+ // Given
+ mockLines := []files.Line{
+ {LineNumber: 1, Text: "", IsCommentedLine: false},
+ }
+ mockFile := files.File{
+ Lines: mockLines,
+ FileName: "test.page",
+ IgnoresSelected: []files.IgnoreSelected{},
+ }
+ // openScriptStyleTagRegexp matches "" starts at absolute index 48, closeTagMatch[0] = 48-7 = 41.
+ // ColumnRange = [7, 7+41] = [7, 48].
+ expectedResult := []rules.Occurrence{
+ {
+ LineContent: "",
+ LineNumber: 1,
+ ColumnRange: []int{7, 48},
+ IsFalsePositive: false,
+ },
+ }
+
+ // When
+ actualResult := findVulnerableLinesBetweenTags(mockFile, "XSSCurrentPageParameters", []string{}, false)
+
+ // Then
+ if !reflect.DeepEqual(actualResult, expectedResult) {
+ t.Errorf("%s Actual: %+v, Expected: %+v", "Occurrences list should be equal!", actualResult, expectedResult)
+ }
+}
+
+// TestFindVulnerableLinesCloseTagFollowedByOpenTagKeepsState verifies that when a
+// closing tag is immediately followed by a new opening tag on the same line,
+// hasOpeningScriptOrStyleTagFound remains true and subsequent lines are still scanned.
+func TestFindVulnerableLinesCloseTagFollowedByOpenTagKeepsState(t *testing.T) {
+ // Given - line 2 closes and re-opens a script block; line 3 should still be scanned
+ mockLines := []files.Line{
+ {LineNumber: 1, Text: "", IsCommentedLine: false},
+ }
+ mockFile := files.File{
+ Lines: mockLines,
+ FileName: "test.page",
+ IgnoresSelected: []files.IgnoreSelected{},
+ }
+ expectedResult := []rules.Occurrence{
+ {LineContent: "", LineNumber: 4, IsFalsePositive: false},
+ }
+
+ // When
+ actualResult := findVulnerableLinesBetweenTags(mockFile, "XSSCurrentPageParameters", []string{}, false)
+
+ // Then
+ if !reflect.DeepEqual(actualResult, expectedResult) {
+ t.Errorf("%s Actual: %+v, Expected: %+v", "Occurrences list should be equal!", actualResult, expectedResult)
+ }
+}
+
+// TestFindVulnerableLinesColumnRangeLessThanGuard verifies the columnRange[0] < columnRange[1]
+// guard introduced in the last commit. When closeTagMatch is nil (close tag not found after
+// openTagEnd), columnRange stays [0,0] and the < condition correctly prevents appending a
+// spurious ColumnRange. The line is still reported (as part of the opening-tag line) but
+// without a ColumnRange field.
+func TestFindVulnerableLinesColumnRangeLessThanGuard(t *testing.T) {
+ // Given - a self-closing-like line where openScriptStyleTagRegexp matches but
+ // closeScriptStyleTagRegexp also matches, yet the close tag appears BEFORE openTagEnd
+ // when searched from line.Text[openTagEnd:] → closeTagMatch is nil → columnRange = [0,0].
+ // Construct: "", IsCommentedLine: false},
+ }
+ mockFile := files.File{
+ Lines: mockLines,
+ FileName: "test.page",
+ IgnoresSelected: []files.IgnoreSelected{},
+ }
+
+ // When
+ actualResult := findVulnerableLinesBetweenTags(mockFile, "XSSCurrentPageParameters", []string{}, false)
+
+ // Then - ColumnRange [7, 14] is valid (7 < 14), so exactly one occurrence with a ColumnRange.
+ if len(actualResult) != 1 {
+ t.Fatalf("Expected 1 occurrence, got %d: %+v", len(actualResult), actualResult)
+ }
+ if len(actualResult[0].ColumnRange) != 2 {
+ t.Errorf("Expected a ColumnRange on the occurrence, got: %+v", actualResult[0])
+ }
+ if actualResult[0].ColumnRange[0] >= actualResult[0].ColumnRange[1] {
+ t.Errorf("columnRange[0] must be < columnRange[1], got: %+v", actualResult[0].ColumnRange)
+ }
+}