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:
- Navigate to Findings from the left sidebar
- Click a finding row to open the magic panel
-
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
-
The finding's status updates immediately
- Click the next finding row to continue triaging
From the Finding Detail Page¶
For a more thorough review before triaging:
- Click the finding title or the View Details link in the magic panel
- Review the full description, code snippet, CWE/CVE references, and remediation guidance
- Use the Status dropdown and Reason field in the detail page header
- 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¶
- Navigate to the Findings page
- Use filters to narrow to the findings you want to triage (e.g., filter by Rule ID or scanner)
- Select findings using the checkboxes on each row
- Use the header checkbox to select all findings on the current page
- Click the Bulk Update button in the action bar
-
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¶
- Viewing & Filtering — Navigate the findings table
- Finding Details — Full detail view for individual findings
- Findings Overview — The unified findings model