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:

SurfaceHow
DashboardProjects 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
GitHubComment /cygent audit on the default branch or a specific PR
ScheduledAs 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.

SeverityWhat it meansAction cadence
CriticalDirect drain of funds, brick the protocol, admin takeoverFix before next deploy — do not merge
HighSignificant damage with non-trivial setup (flash loan, governance, specific market conditions)Fix before mainnet; quickly if already deployed
MediumNotable issue, specific conditions required or partial lossRemediate in the normal release cycle
LowMinor concern, likely not exploitable but a deviation from best practiceFix when convenient
InformationalStyle, gas optimization, documentation clarity, unused codeCleanup 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  │
                      └──────────┘
StateMeaning
ActiveThe default state. A real, unresolved finding. Your work queue.
ResolvedFixed. Often set automatically when the linked GitHub issue closes.
InvalidNot a real vulnerability in this protocol. False positive or unreachable textbook pattern. Always with a reason.
DeletedSoft-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:

ActionWhen to use
Mark InvalidReject a false positive. Always include a reason — feeds Cygent's understanding of your protocol
Mark ResolvedIndicate the issue has been fixed. Often set automatically when a linked GitHub issue closes
Create GitHub IssueFile a GitHub issue from the finding with full context. Status syncs back automatically
Add Manual FindingCreate a finding manually for something noticed outside an automated audit
RestoreBring an Invalid or Deleted finding back to Active if the decision was wrong
DeleteSoft-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.

The dashboard's finding browser supports:

FilterValues
SeverityCritical / High / Medium / Low / Info
StatusActive / Resolved / Invalid / Deleted
Text searchMatch on title, description, or file path
Expandable detailsClick 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:

SettingNotes
Severity thresholdTypically High — Medium creates noise, Critical-only misses things worth tracking
Per-project overrideMain protocol deserves lower threshold; experimental repos, higher
Sync backWhen 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:

FieldWhat it shows
Title + descriptionWhat the issue is
Root causeWhy the code is vulnerable
RecommendationHow to fix it, often with a concrete code snippet
Attack vectorHow an attacker would actually exploit this
Affected codeFile, line range, contract, function — highlighted inline
Proof of conceptPoC code demonstrating the exploit (for some findings)
Linked resourcesGitHub issue, PR that fixed it, related findings