Skip to content

Triage Workflow

Triage is the process of reviewing security findings and deciding what action to take. Mayo ASPM provides a structured workflow with defined status transitions, bulk operations, and audit tracking to make triage efficient and accountable.


Status Transitions

Findings move through a defined set of statuses. Not all transitions are valid — the workflow enforces a logical progression:

Status Definitions

Status Meaning Next Steps
Open Newly detected, not yet reviewed by anyone Triage to any other status
Confirmed Reviewed and confirmed as a real vulnerability Assign to a developer, begin fix
In Progress A fix is actively being worked on Complete the fix and resolve
Resolved The vulnerability has been fixed No further action needed
False Positive The finding was reviewed and determined not to be a real issue No further action needed
Accepted Risk The finding is real but the team has decided to accept the risk Document the justification

Valid Transitions

Open ──────────▶ Confirmed ──────────▶ In Progress ──────────▶ Resolved
  │                                         │
  ├──────────▶ False Positive               │
  │                                         │
  ├──────────▶ Accepted Risk                │
  │                                         │
  └──────────▶ Resolved (direct)            │
In Progress ──▶ Accepted Risk               │
Confirmed ────▶ False Positive              │
              ▶ Accepted Risk               │

Reopening Findings

If a resolved finding reappears in a subsequent scan (meaning the code was not actually fixed), Mayo ASPM automatically transitions it back to Open. This prevents findings from being marked resolved while the vulnerability still exists.


Triaging a Single Finding

From the Magic Panel

The fastest way to triage is through the magic panel on the Findings page:

  1. Navigate to Findings from the left sidebar
  2. Click a finding row to open the magic panel
  3. In the Triage section at the bottom of the panel:

    a. Select a new status from the dropdown

    b. Enter a triage reason (required for False Positive and Accepted Risk, optional for other transitions)

    c. Click Update

  4. The finding's status updates immediately

  5. Click the next finding row to continue triaging

From the Finding Detail Page

For a more thorough review before triaging:

  1. Click the finding title or the View Details link in the magic panel
  2. Review the full description, code snippet, CWE/CVE references, and remediation guidance
  3. Use the Status dropdown and Reason field in the detail page header
  4. Click Update

Triage Reason Field

The triage reason field provides context for status transitions. It is:

Transition Reason Required? Example Reason
Open to Confirmed Optional "Verified: this endpoint accepts unsanitized user input"
Open to In Progress Optional "Assigned to @developer, fix in sprint 23"
Open to Resolved Optional "Fixed in commit abc123"
Open to False Positive Required "This is a test file with intentional vulnerable patterns for security training"
Open to Accepted Risk Required "Internal-only endpoint behind VPN, risk accepted per security review SR-2026-042"
Confirmed to In Progress Optional "Working on parameterized query refactor"
Confirmed to False Positive Required "Rule triggered on a comment, not executable code"
Confirmed to Accepted Risk Required "Mitigated by WAF rule, residual risk accepted"
In Progress to Resolved Optional "Fix deployed in v2.1.4"
In Progress to Accepted Risk Required "Fix too complex for current sprint, risk accepted until Q3"

Justify Dismissals

False Positive and Accepted Risk statuses always require a reason. This creates an audit trail that explains why the finding was not fixed — critical for compliance and security reviews.


Who Triaged and When

Every status change is recorded with:

Metadata Description
User The email address of the user who made the status change
Timestamp When the status change occurred (UTC)
Previous status What the status was before the change
New status What the status was changed to
Reason The triage reason provided (if any)

This audit trail is visible on the finding's detail page in the History section:

2026-04-15 14:30 UTC — jane@company.com
  Changed status: Open → Confirmed
  Reason: "Verified SQL injection via manual testing"

2026-04-15 16:45 UTC — john@company.com
  Changed status: Confirmed → In Progress
  Reason: "Fix assigned, PR #234 in progress"

2026-04-16 09:12 UTC — john@company.com
  Changed status: In Progress → Resolved
  Reason: "Fix merged in PR #234"

Bulk Triage

When you need to triage many findings at once — for example, dismissing a batch of false positives from a noisy rule — use bulk update.

Steps

  1. Navigate to the Findings page
  2. Use filters to narrow to the findings you want to triage (e.g., filter by Rule ID or scanner)
  3. Select findings using the checkboxes on each row
  4. Use the header checkbox to select all findings on the current page
  5. Click the Bulk Update button in the action bar
  6. In the bulk update modal:

    a. Select the new status

    b. Enter a triage reason (required for False Positive and Accepted Risk)

    c. Click Apply to N findings

Efficient Bulk Triage

Use filters and search to isolate a group of related findings before selecting and bulk-updating. For example:

  • Filter by Rule ID generic-api-key + Status: Open, then bulk mark as False Positive if they are all in example/test files
  • Filter by Scanner: Trivy + Severity: Low, then bulk mark as Accepted Risk for low-priority dependency findings

Bulk Update Confirmation

A confirmation dialog shows:

┌─────────────────────────────────────────────┐
│  Bulk Status Update                         │
│                                             │
│  Update 15 findings to: False Positive      │
│                                             │
│  Reason: "Test fixtures with intentional    │
│  vulnerable patterns — not production code" │
│                                             │
│           [Cancel]     [Apply]              │
└─────────────────────────────────────────────┘

Triage Best Practices

1. Triage by Severity

Start with Critical findings, then High, then Medium. Low findings can often be batch-triaged.

2. Use Consistent Reasons

Develop standard language for common triage decisions:

Scenario Suggested Reason Template
Test file false positive "Finding in test/mock file — not production code"
WAF mitigation "Mitigated by WAF rule [RULE-ID], accepted risk"
Known internal pattern "Internal API behind authentication, risk accepted per [ticket]"
Dependency update planned "Upgrade tracked in [ticket], in progress for [sprint]"

3. Never Dismiss Without Context

Every False Positive and Accepted Risk should have a reason that a future reviewer can understand. "Not a real issue" is insufficient — explain why it is not a real issue.

4. Review Accepted Risks Periodically

Set a calendar reminder to review Accepted Risk findings quarterly. Conditions change — a previously acceptable risk may become unacceptable as the application evolves.


OPA-Automated Triage

For organizations with consistent triage patterns, OPA triage policies can automate status transitions:

package mayo.triage

# Auto-confirm critical and high findings
status = "confirmed" {
    input.finding.severity in ["critical", "high"]
}

# Auto-dismiss findings in vendored code
status = "false_positive" {
    startswith(input.finding.file_path, "vendor/")
}
reason = "Vendored third-party code — not maintained by this team" {
    startswith(input.finding.file_path, "vendor/")
}

See Triage Policy for full documentation on automated triage.


Next Steps