Maintaining
Maintaining keeps a codebase healthy after it ships. It sweeps the linked repository for vulnerable dependencies, committed secrets, insecure code patterns and infrastructure misconfigurations, records what it finds, and can turn a finding into a pull request.
Working through findings
Section titled “Working through findings”Findings are split by kind: vulnerable dependencies, secrets, insecure code and misconfigurations, with your policies alongside them, because each kind is fixed differently. A dependency is bumped, a secret is rotated, insecure code is fixed where it sits, and a policy is met by what your documents say.
Within each kind, work from the top priority tier down. A finding whose fix is already under way keeps its tier and links to the initiative doing the work, so you can tell what is still waiting on a decision from what is only waiting on the fix. Findings on one version of one package are fixed together, in one initiative. The first backlog of an imported repository leaves out a finding Maintaining can fix in one click, unless another initiative builds on it or it is all there is to plan; fixing it here raises an initiative of its own.
Before trusting a quiet list, check when the product was last swept and whether that sweep succeeded. A clean board from a sweep that last ran months ago is not evidence of anything. The page says when the product was last checked. A product that has never been swept says so rather than showing an all-clear, and a sweep that failed is reported as a failure, not as a clean result.
Policy controls affected
Section titled “Policy controls affected”Where findings breach controls in your own published policies, the finding’s own page names them:
SEC-3.4, SCS-2.6, and so on.
These are your control identifiers, not Taiga’s. Only controls that appear in the policy you actually publish are shown, so a control you rewrote or removed is never cited against you. A finding with no matching control is still reported in full; it simply carries no control alongside it, which is the honest answer when your policies do not speak to it.
The mapping is deliberately conservative. A weak hashing algorithm, for example, is reported as a finding but mapped to no control, because the nearest candidate governs encryption at rest, which is a different thing. Naming it would tell you that you breached a control you did not.
Each opens the policy that defines it, at the control.
Sweeps run themselves
Section titled “Sweeps run themselves”A sweep clones the repository and scans it. You do not have to ask for one.
Taiga sweeps a product when either of two things is true:
- Your code changed. A push to the linked repository marks the product as due, so a sweep follows the work rather than a calendar.
- Enough time has passed. Every product is swept periodically even when nothing changed, because the other half of a finding is the advisory database, and that moves on its own. A dependency you have not touched can become a vulnerability overnight.
Products are enrolled automatically once they have a linked repository. There is nothing to switch on.
Every sweep is kept, so the record shows both what is wrong now and when it was last checked.
A build runs the same scans before it opens its pull request, but it fixes only what its own change introduced, or a finding its initiative names by its advisory id (a CVE, a GHSA, or an ecosystem id such as GO- or RUSTSEC-) or its scanner rule id.
Everything else the scans see is left to Maintaining, so a feature pull request never carries dependency bumps or security fixes nobody asked for.
What a sweep checks
Section titled “What a sweep checks”Four kinds of finding, each found by its own independent scan:
| Finding kind | What it catches |
|---|---|
| Vulnerable / outdated dependency | A package in a lockfile or manifest with a known advisory (CVE / GHSA) |
| Secret | A credential committed to the repository, in the current files or in any earlier commit on the default branch: private keys, cloud and API tokens |
| Insecure code | A code pattern a security reviewer would flag on sight: SQL built from strings, shell commands from input, disabled TLS verification, unsafe deserialization |
| Infrastructure misconfiguration | Terraform, Kubernetes, Dockerfile and CI configuration that exposes or under-protects something: public buckets, open security groups, unencrypted storage |
If one scan fails or times out, the others still report, and the failed scan’s earlier findings are left as they were rather than marked fixed. Silence from a scan that did not run is not a clean bill of health.
Test fixtures are treated for what they are: insecure code and misconfigurations under test directories are not reported, and a secret in a test fixture is reported at a lower severity.
The scans follow what your repository already says to leave alone.
A .checkov.yml or .checkov.yaml applies its skip-check and skip-path entries to the files under it, wherever it sits in the repository, not only at the root.
Inline checkov:skip, nosemgrep and gitleaks:allow comments apply where they are written,
and .semgrepignore, osv-scanner.toml, .gitleaks.toml, .betterleaksignore and .gitleaksignore apply as those tools define them,
including ignore entries pinned to a commit, which also cover the same secret where it still sits in that file today.
When one of those .checkov.yml entries or commit-pinned ignore entries covers a finding Taiga has already reported,
the finding is shown as ignored, with the reason Accepted risk and a note naming the file and entry, rather than as fixed;
if the entry is removed later, the finding reopens.
A suppression narrows what is reported, not what is scanned: Taiga still scans files your own CI does not.
The value of a detected secret is never stored. The finding names the rule, the file and the line; rotating the credential and removing it from the repository is the fix.
Secrets are looked for in the repository’s history as well as in its current files, because a credential deleted in a later commit is still readable by anyone who can clone the repository. A secret that exists only in history is marked Git history only, and its page names the commit it was found in and links the file as it was in that commit. Commit authors, email addresses and messages are not stored.
Findings
Section titled “Findings”Findings are grouped rather than listed one per line: dependency findings by package, code and infrastructure findings by rule, and a rule group is titled by what the rule says; a group with one finding also says where it is, and the rule’s identifier is on the group’s page. A group with one finding is shown as that finding. Either kind of group can be remediated as one: a package group plans a single version bump that clears every advisory on it, and a rule group plans a single fix that has to leave every flagged location clean. One outdated dependency causing six problems is one thing to decide about, not six, and so is one misconfiguration repeated across four resources. A group that also holds findings in a submodule counts only the ones Taiga can fix here: before the fix runs, the confirmation says how many findings it clears and names the ones that are not part of it.
Each group opens a page of its own. The group’s findings are listed beside the page, and the one you pick is shown in full: what it is, how likely it is to be exploited, the fix, its history, and a references block that is the same for every kind of finding, the advisory and its links, the lockfiles a package resolves in, the place in the code with the lines, or the policy and the document passages. What the whole group shares, why it is ranked where it is, the package or rule, and the policy controls it breaches, stays beside the list. Fix on that page plans the whole group, as it does on the list. A single finding in the group can also be fixed on its own; for a dependency, that bumps only as far as that one advisory needs.
A code finding names the file and line it was found at and the rule that flagged it; its detail page links straight to that line in your repository. A secret finding names the rule and the location only: the matched value is never stored.
Two things to do with a finding:
| Action | When |
|---|---|
| Ignore | It is not applicable to you, or you accept it. Ignored findings are kept and reviewable, not deleted. |
| Fix | You want the fix. Taiga queues it and plans it in turn; whether the build then waits for you is the line’s autonomy setting. Absent on a secret that is only in history, on anything inside a submodule, and on a dependency with no fixed version to move to; the page explains instead. |
There is no button for “fixed”, on purpose. A finding you have dealt with resolves itself when the next sweep no longer detects it, so a resolved finding means the scan agrees it is gone, not that somebody said so. And if a resolved finding ever comes back, it reopens rather than appearing as something new, so a recurring problem carries its history with it.
Ignoring asks you why, from a fixed set of reasons, and can be given an expiry, after which the finding resurfaces if it still exists. Ignored and resolved findings stay on the page below the open ones, and you can reopen an ignored one.
Acting on a finding is member-level, not an administrator task. Whoever notices the problem can deal with it.
What remediating actually changes
Section titled “What remediating actually changes”Fix works on every kind of finding, with three exceptions: a secret that is only in history, code that belongs to a submodule, and a dependency with no fixed version to move to. Otherwise the fix is a different shape depending on what was found.
For a vulnerable dependency, the fix is a version. Taiga raises the package to a release that clears the advisory, across every place it resolves, and the remediation is done when no copy below the fixed version remains. A dependency with no release that clears the advisory has no Fix. A malicious package is the sharpest case: the finding says there is no safe version to move to, and the fix is to remove the package, and whatever pulls it in, by hand. The next sweep confirms it is gone.
For insecure code and infrastructure misconfiguration, the fix is a change to the code or the resource: a parameterised query instead of an interpolated one, an encryption attribute set on the database. There is no version involved, so the test is the scanner itself. The remediation is done when the same rule runs over the same file and no longer matches, which is why suppressing the rule does not count and neither does moving the pattern somewhere the rule cannot see it.
For a committed secret, Taiga does half the job and tells you so.
It takes the credential out of the tracked source and moves the application onto a configured value. What it cannot do is make the exposed credential safe: the value is in your repository history, anyone who cloned the repository has it, and it stays valid until somebody revokes it in the system that issued it. So the pull request says, in its own description, that the credential still needs rotating and has not been rotated.
Rotate first if you can. The code change is worth making either way, because it stops the value being committed again, but it is not the part that closes the exposure.
A secret found only in history has no Fix, because there is nothing in the current files to change. Rotating the credential is the whole fix, and it happens outside Taiga. Once you have rotated it, ignore the finding with a reason. The finding resolves on its own only if the commit disappears from the branch’s history, which means rewriting history: that is optional and your decision. A secret that a Fix removed from the files ends up the same way: after the merge, the next sweep reopens it as history-only, and it stays open until you rotate the credential and ignore it.
Findings inside a submodule
Section titled “Findings inside a submodule”A submodule is another repository, checked out inside yours and pinned at one commit. Sweeps read its files, so findings in it are reported rather than hidden, and they carry the severity and the advisory they would carry anywhere else.
They have no Fix. Taiga never writes inside a submodule, because the change would belong to a repository this one only points at, and a commit made there could not be pushed from here. The finding says so instead: it names the submodule, links its upstream repository, and shows the commit your repository pins.
Make the fix in that repository, then move your pin to a commit that includes it. The finding resolves on its own once a sweep no longer detects it, the same as any other, so nothing needs marking as fixed here.
Ignore is still available if the finding is not applicable to you.
Policies
Section titled “Policies”Policies answer a different question from the findings: not “what did the scanners find” but “where does this product stand against our own policies”.
Work through the controls your product violates starting with the most severe, critical before high, and check how many of each control’s violations already have an initiative before raising another.
A control with no violation is not reported, and it is not “passing” either: there is no such state, on purpose. That includes a control that only scanner findings breach; those are named on the finding, not here. A control nobody has found anything against is a control nobody has found anything against.
Each violated control has a page of its own. For each violation you can read the assessment’s account of it, what is being done about it, the control’s own wording, and the passages from your documents the assessment rests on, each labeled with its document and section. From there you can open the policy at the control, see when the documents were last assessed, and find the scanner findings and initiatives that concern the same control.
The document assessment
Section titled “The document assessment”Scanners see code patterns. They cannot tell you that personal data is kept with no retention limit, or that a service stores something in plaintext that your data policy says must be encrypted. That comparison needs the product’s reality documents, the architecture, data flow, privacy assessment, threat model and risk register that an import derives from the repository, read against the text of your policies.
The assessment makes that comparison. It records each place the documents contradict a control as a violation, and every violation carries three things: the control’s sentence it was compared against, the passage from the document that contradicts it, and which documents were read. You can check each claim without opening either the policy or the document.
An assessment reports critical and high violations only. A softer violation is noise at the moment you are deciding whether this tool understands your system, and a violation Taiga cannot cite is not reported at all. Only controls that appear in the policies you actually publish can be cited, so a control you rewrote or removed is never held against you.
The first assessment runs on its own when an import finishes, and another follows every refresh of the reality documents, including the refresh a push to your integration branch triggers. The tab says which commit the documents describe and when they were derived, separately from when they were assessed, because those are different questions: a fresh assessment of stale documents is still a stale answer.
A re-assessment is shown the violations already recorded and answers for each one: it either confirms the violation with the passage that still records it, or records that the documents no longer support it, which resolves the violation. A violation it does neither for stays open and is marked Not reproduced on the control’s page, with how long that has been so. Silence is not a fix: a violation the assessment happened not to repeat is still a violation until one positively records that the documents no longer show it. Violations are findings, not work: they tell you where the product stands, and raising an initiative to close one is a separate decision on the Initiatives page.
A control with open violations has a Fix that covers every violation recorded against it that has no initiative yet. It raises one initiative and adds it to the end of the product’s queue, exactly as Fix does for a finding: the line plans it against the repository when its turn comes, and the initiative says whether the build then starts on its own or waits for you. The violation stays listed while that work is under way, because only the next assessment can record that the documents no longer support it.
Plan initiatives reads the same ledger. On a brownfield product, planning initiatives takes the open violations into account beside the scanner findings, and each policy initiative you get names the violations it closes. After planning, you can see for each control how many of its violations have an initiative.
A violation that appears after a push to your integration branch is news, whether it is new or a resolved one back again, and the inbox says so: one item per product asking you to review policy violations, counting the ones that appeared after the commit and linking to this tab. Violations found at import are the baseline you curate; they never raise an item, and neither does a re-assessment that only confirms what was already recorded.
When an initiative addressing a violation is done, the next assessment is asked for an explicit verdict on it. The violation shows Awaiting verification until then; if the refreshed documents no longer record the violation it resolves and leaves the tab, and if they still do it stays open and shows Still recorded after fix, naming the initiative, so a shipped fix that did not change the documents is never mistaken for a resolved violation.
When an initiative exists for a violation, the control’s page says so: the state, naming the initiative. A violation with a fix raised shows Initiative raised, and Fix in progress once a build has started on it; once that initiative is canceled or archived without landing the state says so, and Fix is offered again. A Fix whose plan fails cancels its initiative for the same reason, so a dead plan never holds a violation; an initiative from Plan initiatives is kept instead, where you re-plan it. A control’s Fix covers the open violations that have no initiative of their own; it is offered on the control’s line in the tab and on its page. Fixing a single violation on its own is offered only on the control’s page, and only while the control has more than one violation without an initiative. Each control’s page lists every initiative addressing its findings or its violations. A finding under remediation still counts against its control until the sweep verifies the fix.
Every finding gets a priority, and the rule is public
Section titled “Every finding gets a priority, and the rule is public”Severity says how bad a vulnerability would be if exploited. It says nothing about whether anyone is exploiting it, and those are different questions with different deadlines. So alongside severity, every finding is placed in one of four priority tiers:
| Tier | What it means |
|---|---|
| Act now | Confirmed exploitation: the vulnerability is on CISA’s Known Exploited Vulnerabilities list, or the package itself is a known malicious release. |
| Urgent | Likely and serious: the exploit-prediction score (EPSS) says exploitation is likely, and the severity is high or critical. |
| Elevated | One signal but not both: likely exploited or high severity. |
| Routine | Neither. The long tail, and most findings. |
Two properties of the rule are worth trusting.
It is a fixed rule, not a model’s opinion. The same finding gets the same tier every time, and each tier can be explained in one sentence, which is what makes it auditable. Severity and exploitation likelihood are kept as separate questions rather than multiplied into a single score, because they measure different things.
A data outage never downgrades a finding. When the exploitation feeds are temporarily unavailable, a finding is tiered on severity alone, and an exploitation signal Taiga has already seen is kept rather than forgotten. A known-exploited vulnerability does not become routine because a feed had a bad day.
The top two tiers are queued without being asked
Section titled “The top two tiers are queued without being asked”Findings in Act now and Urgent get their fix raised automatically and added to the end of the product’s queue, where the line plans it in turn, ready for you to run.
Severity alone never triggers this, deliberately. A critical-severity finding that nobody is exploiting waits for you to decide; one that attackers are actively using is worked out in advance. The severity label says how bad it would be, the tier says how urgent it is, and urgency is what earns a plan you did not ask for.
It is bounded on purpose, so it cannot flood you or make a decision you would not have made:
- Only minor and patch upgrades. A major version bump is a breaking change and stays yours to decide.
- A cap on how many are planned per product per day, and a cooldown before the same package is attempted again.
And when a qualifying finding is skipped, because the fix would be a major bump or the daily cap was reached, the skip itself is recorded, so the trail explains what did not happen and why.
The plan waits in your inbox. Running it is your call, the same as any other initiative.
Remediation is always a normal run
Section titled “Remediation is always a normal run”Automatic or requested, a remediation ends in a run like any other. An agent produces the fix on a branch and opens a pull request, and you review and merge it.
Both start the same way, and it is worth being precise about it.
A remediation raises an initiative and adds it to the end of the product’s queue. The line plans it when its turn comes, and you see what the change involves before any code is written; running it is a separate decision that stays yours. A fix that cannot wait is dragged up the queue like any other initiative. From then on the initiative is where the fix lives, through the plan, the run and the pull request, and the finding links to it. The initiative’s description says what the fix achieves and why; the findings it fixes are listed under Evidence on its page.
Taking it off the line ends it. Removing it from the queue before the line has started on it, or moving it out of the queue, the plan or the build into Todo or Backlog, cancels the initiative and puts its findings back on the open list, because nothing outside the line will ever plan it. Removing the entry once the line has already started planning leaves the initiative where the work is, plan and all. Moving that to Todo or Backlog is what ends it. The initiative stays in your history with the findings it named, and Fix raises new work when you want it after all.
Whether the build then starts on its own is the same switch every initiative has for reading the plan first, and the line’s autonomy setting decides its default. It changes when you decide, not what you decide: the pull request is still yours to review and merge.
That is true of an automatic remediation too. Taiga decides on its own that an urgent finding is worth fixing, and queues the fix without being asked, but it stops there: the line plans it in turn, and whether the build then waits for you is the same autonomy setting as for any other initiative. A fix Taiga proposed on its own never opens that gate on its own: the setting is yours, and a fix it raised follows it, never overrides it.
There is no path where a dependency fix goes straight in. A patch that updates a dependency is a change to your code, and it gets the same review as one you asked for. Automatic remediation decides what to propose, never what to merge.
The merge itself is checked rather than assumed. Every fix branch is independently re-scanned, and a vulnerability that survived the fix reopens the finding instead of staying quietly closed. A green pipeline proves the run finished; the re-scan is what says the vulnerability is gone.
That also means everything in when an agent gets it wrong applies here: the run can break, stop on an ambiguity, or produce a fix you disagree with.
What this is not
Section titled “What this is not”It is not a gate. A sweep follows a push rather than blocking it, so a vulnerable dependency can reach your default branch and be found shortly afterward. If you need something to fail the commit, that belongs in your own pipeline.
It also reads the repository, not the running system. It can tell you a dependency is vulnerable; it cannot tell you whether the vulnerable path is reachable in production.
Did you find what you needed?
