Understanding Findings
Kicking off audits, the severity model, the finding lifecycle, and why 'Invalid' is a feature.
Overview
A finding is Cygent's unit of security work. It's what CARA produces when it audits your code, what Cygent Code acts on when it fixes a bug, and what your team triages every week. Understanding the finding lifecycle — how findings are created, what severity actually means, when to mark something Invalid, and how findings sync to GitHub issues — is the difference between "we have Cygent" and "we're getting real value from Cygent."
Kicking off an audit
Audits produce findings. You can trigger one four ways, all equivalent:
| Surface | How |
|---|---|
| Dashboard | Projects tab → select a repo → Run Audit. Optionally scope to a branch, contract, or file |
| Chat | @cygent run a full audit on my-repo or @cygent audit Vault.sol |
| GitHub | Comment /cygent audit on the default branch or a specific PR |
| Scheduled | As a scheduled task on a recurring cadence |
What you see while an audit runs
The audit opens a live progress view on the dashboard:
- Phase indicators — which stage CARA is in (parsing, analysis, reasoning, finalization).
- Progress percentage with an estimated completion time.
- Partial findings — as CARA identifies issues, they start showing up in the finding list before the audit is fully done.
- Log stream — if you want to watch the internals.
Audits run asynchronously — you don't need to sit on the page. A notification lands in your default review channel when complete.
For a tight feedback loop while actively developing, scope audits to specific contracts or files. A full-repo audit is right for periodic deep passes; a contract-scoped audit is right for "I just refactored this, is it safe?"
Severity tiers
Every finding has a severity, chosen by CARA based on exploitability, impact, and likelihood. This is the primary axis you prioritize on.
| Severity | What it means | Action cadence |
|---|---|---|
| Critical | Direct drain of funds, brick the protocol, admin takeover | Fix before next deploy — do not merge |
| High | Significant damage with non-trivial setup (flash loan, governance, specific market conditions) | Fix before mainnet; quickly if already deployed |
| Medium | Notable issue, specific conditions required or partial loss | Remediate in the normal release cycle |
| Low | Minor concern, likely not exploitable but a deviation from best practice | Fix when convenient |
| Informational | Style, gas optimization, documentation clarity, unused code | Cleanup passes |
Prioritization in practice
Critical and High findings deserve immediate attention. A pragmatic cadence: triage Criticals within the day they surface, Highs within the week, Mediums within the release, and Lows/Infos in a batched cleanup pass.
Don't treat severity as a fixed absolute. A Medium in a function handling billions of TVL may be more urgent in practice than a High in an unreachable internal helper. Severity is the first signal, not the last word.
The finding lifecycle
Every finding moves through a small set of states. You — or Cygent — transitions findings between these states as work progresses.
┌──────────┐
│ Active │ ◄──── default state
└────┬─────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Resolved │ │ Invalid │ │ Deleted │
└──────────┘ └────┬─────┘ └────┬─────┘
│ │
└──── Restore ─┘
│
▼
┌──────────┐
│ Active │
└──────────┘
| State | Meaning |
|---|---|
| Active | The default state. A real, unresolved finding. Your work queue. |
| Resolved | Fixed. Often set automatically when the linked GitHub issue closes. |
| Invalid | Not a real vulnerability in this protocol. False positive or unreachable textbook pattern. Always with a reason. |
| Deleted | Soft-deleted. Not visible in normal views but recoverable. Use sparingly — Invalid is usually the right call. |
Why "Invalid" matters
This is the most misunderstood part of the product, and it's worth a dedicated section.
A scanner-only tool dumps every pattern-match it finds on you and walks away. If the tool sees an external call followed by a state update, it flags reentrancy. The fact that your protocol only supports WETH and USDC — tokens with no callback hooks, where reentrancy is physically impossible — is not something the tool cares about.
Cygent does care. Consider this actual pattern from the GhostLend demo:
function withdrawCollateral(address token, uint256 amount) external {
emit CollateralWithdrawn(msg.sender, token, amount);
IERC20(token).safeTransfer(msg.sender, amount); // external call
s_collateral[msg.sender][token] -= amount; // state update after
}
Textbook CEI violation. A pattern-matcher would file it Critical, every time.
Cygent marks it Invalid, with a recorded reason:
Classic checks-effects-interactions violation. However, this protocol only supports WETH and USDC as collateral. Neither token has callback hooks or transfer hooks that could be exploited for reentrancy. The code is bad practice and should be refactored for future-proofing, but it is not currently exploitable. Downgrading from Critical to Invalid. Flagging as a note for when new tokens are added.
That decision saves the team an afternoon. Nobody pages the oncall, nobody sprints to fix a non-bug. The finding is recorded — including the reason it's invalid — so that if the team later adds a token with a callback hook, the decision can be revisited.
The rule: if a finding is real, keep it Active or move it to Resolved. If a finding is textbook-correct but not exploitable in your protocol, mark it Invalid with a reason. Invalid is not a failure; it's the outcome of the agent reasoning through the specifics.
Triage actions
Actions you can take on a finding, from the dashboard, from chat, or from an MCP-connected IDE:
| Action | When to use |
|---|---|
| Mark Invalid | Reject a false positive. Always include a reason — feeds Cygent's understanding of your protocol |
| Mark Resolved | Indicate the issue has been fixed. Often set automatically when a linked GitHub issue closes |
| Create GitHub Issue | File a GitHub issue from the finding with full context. Status syncs back automatically |
| Add Manual Finding | Create a finding manually for something noticed outside an automated audit |
| Restore | Bring an Invalid or Deleted finding back to Active if the decision was wrong |
| Delete | Soft-delete a truly irrelevant finding. Recoverable if needed |
Bulk triage
For findings that need the same action in bulk — say, ten low-severity informational findings about natspec style — the dashboard supports multi-select. Check the boxes, apply the action. You can also drive bulk triage from chat:
@cygent mark all Info findings on Vault.sol as Invalid with reason "style only, not tracking"@cygent mark findings L-1 through L-4 as Resolved
Bulk triage is especially valuable after a refactor — findings that reference code that no longer exists can all be moved together.
Filtering and search
The dashboard's finding browser supports:
| Filter | Values |
|---|---|
| Severity | Critical / High / Medium / Low / Info |
| Status | Active / Resolved / Invalid / Deleted |
| Text search | Match on title, description, or file path |
| Expandable details | Click any finding for affected code, recommendation, attack vector, linked issues |
The common filter is Severity ≥ High AND Status = Active — that's your live work queue.
GitHub issue auto-creation
You can have Cygent file GitHub issues automatically for findings at or above a severity threshold. Configure in Settings → Auto-create issues:
| Setting | Notes |
|---|---|
| Severity threshold | Typically High — Medium creates noise, Critical-only misses things worth tracking |
| Per-project override | Main protocol deserves lower threshold; experimental repos, higher |
| Sync back | When the GitHub issue closes, the finding moves to Resolved. /cygent fixed comment does the same |
The sync is bidirectional enough to matter: your GitHub issue tracker and your Cygent finding backlog don't drift apart.
See Behavior & Autonomy for how auto-issue creation fits into the wider autonomy configuration.
Finding details and attack context
Clicking into a finding opens the full detail view:
| Field | What it shows |
|---|---|
| Title + description | What the issue is |
| Root cause | Why the code is vulnerable |
| Recommendation | How to fix it, often with a concrete code snippet |
| Attack vector | How an attacker would actually exploit this |
| Affected code | File, line range, contract, function — highlighted inline |
| Proof of concept | PoC code demonstrating the exploit (for some findings) |
| Linked resources | GitHub issue, PR that fixed it, related findings |