Set up Vulnerability Remediation
Takeaways
- Vulnerability Remediation is a second capability of the Tessl Reviewer GitHub App. It scans a pull request for the vulnerabilities that pull request introduced, fixes the ones the scanner reports a fix for, and verifies each fix with a rescan.
- Turn it on per repository, choose Snyk or Semgrep and Dependabot as the scanner, and choose whether Tessl pushes a fix commit or posts the fix as review suggestions.
- Ask for a run with
@tessl-remediationon the pull request. Read the result in the status comment and theTessl Vulnerability Remediationcheck.
Vulnerability Remediation is in early access. If your organization doesn't have it yet, contact us for early access. Once it does, the Reviewer page shows a Vulnerability Remediation tab.
Agents open pull requests faster than a security team can read them, and a scanner that only reports findings leaves the fixing to a person. Vulnerability Remediation closes that gap on each pull request: it scans the change, attempts a fix for every finding it is able to fix, rescans to verify each fix, and reports on the pull request. Nothing is pushed unless a rescan no longer reports the finding.
Runs use Tessl's infrastructure and the same GitHub App as Code Review. Each run uses tokens minted for that run and scoped to the single repository.
Before you start
Vulnerability Remediation needs the Tessl Reviewer GitHub App installed and the repository reachable by it. If you have already set up Code Review, both are done. If not, follow Step 1 of Set up Tessl Code Review, then come back here. Installing the App does not start anything: you also turn Vulnerability Remediation on per repository, below.
Each capability of the App is turned on separately. A repository with Code Review on and Vulnerability Remediation off gets reviews and no remediation, and the other way around. You don't need Code Review on to use Vulnerability Remediation.
Step 1: Connect Snyk
Snyk is the default scanner, and it scans with your own Snyk account. Skip this step if the repository will use Semgrep or Dependabot, which need no connection.
- Sign in to tessl.io, select your organization, and open Reviewer in the sidebar, then the Vulnerability Remediation tab.
- Select Connect Snyk.
- Enter a Snyk API token and the ID of the Snyk organization to scan under, then save.
The connection is organization-wide: every repository that scans with Snyk uses it. Connecting needs the organization's manage-integrations permission, so a repository admin without it sees Ask an organization manager to connect Snyk.
Tessl checks the token against Snyk before saving it. A rejected token or an organization the token can't reach is reported and nothing is saved. The token is stored encrypted, is never shown again, and is used only while a run scans. It never appears in a log, a result, or a fix. To rotate it, select Replace and enter the new one.
Step 2: Turn it on for a repository
- On the Vulnerability Remediation tab, select the repository.
- Switch on Turn on for this repository.
- Choose the Mode and the Scanners, described below, and save.
Changing a repository's settings needs the organization's manage-integrations permission.
A repository the App can reach but that you haven't turned on is never scanned, however many times someone comments. If its settings have never been saved, a comment gets no reply. If it was turned on and then off, a comment gets a reply saying it isn't enabled.
Choose the mode
Mode decides what a run does with a verified fix.
- Fix. Tessl pushes one fix commit to the pull request branch, then asks Code Review to review that commit. This is the default.
- Advisory. Tessl posts each fix as a review suggestion you apply yourself, and never pushes. A fix GitHub can't show as a suggestion, such as a regenerated lockfile, is carried in the review body instead.
In either mode a fix is only published once a rescan no longer reports the finding it fixes.
Choose the scanners
Snyk runs on its own. Semgrep and Dependabot scan different things, so you can run either or both; when both are on, Semgrep finishes before Dependabot starts, and one run works through both scanners' findings.
Every scanner reports only what the pull request introduced. A code or infrastructure finding has to land on a changed line, a dependency finding has to belong to a dependency the pull request added or changed, and a container finding has to come from a changed Dockerfile that selects a new base image. Vulnerabilities already on the base branch aren't reported.
A changed file the scanner didn't examine is listed in the result under Not scanned, with the reason, rather than treated as clean. Dependency scanning needs a lockfile the scanner can read without installing the project: npm, pnpm, Yarn, Bun, uv, and Poetry lockfiles are scanned, and other ecosystems are listed as not scanned.
Snyk test allowance
Snyk doesn't charge per scan, but each scan a run makes counts as a test against your Snyk plan's monthly allowance, in the same way a snyk test from a terminal does. Snyk counts one test per lockfile or base image a scan examines, so a run uses tests before it starts and again on each rescan after a fix attempt. A run that fixes several findings uses several tests. Snyk's own definition of a test is in What counts as a test. The Semgrep and Dependabot scanners have no allowance.
Ask for a run by comment
Comment on the pull request, on the Conversation tab or inline on the diff. The comment has to contain @tessl-remediation as plain text, not quoted or in backticks.
@tessl-remediationstarts a run: scan, fix, rescan, publish.@tessl-remediation scanscans and fixes nothing. The result lists the findings a run would attempt under Fixable, so you can see what a run would change before asking for it, or confirm a head after applying advisory suggestions. A scan doesn't count toward the limits below.@tessl-remediation undoreverts the fix commit of the latest run that pushed one, as a new commit, without force-pushing. If a later commit changed a file the fix touched, the reply gives thegit revertcommand to run by hand instead.
Anyone with write access to the repository can ask. A comment from anyone else gets a reply saying so. Automated agents can be allowed too; ask us to add their logins to the repository's trusted requesters. A trusted requester can start runs and scans, but only someone with write access can undo.
Two check actions also start runs. Re-run on the Tessl Vulnerability Remediation check runs the same kind of run again, scan or fix, on the current head. Re-run all checks does the same, but only on a pull request where remediation has already run, so turning the capability on doesn't add a run to every re-run of Code Review.
Each run gets its own status comment, edited in place as the run goes, and one check on the head it ran on. One run at a time: a second comment while a run is queued or running gets a reply saying so and starts nothing.
What a run fixes
A run attempts every finding the scanner reports a fix for and leaves the rest for a person:
- A dependency or container finding is attempted when the scanner names a fixed version, or a base image, that clears it.
- A code or infrastructure finding is attempted when the scanner gives a fix hint.
- Everything else is listed under No automatic fix, with the scanner's guidance where it gave any.
A few findings with a scanner fix are still left for you, under No automatic fix: an upgrade that crosses a major version (or a minor version below 1.0), since its breaking changes need a decision, and a fix that needs a new dependency added. The result says which rule applied.
For a code finding it can edit the flagged file. For a Snyk code finding it can also edit any other file the pull request changed along the vulnerable data flow; a Semgrep fix stays in the flagged file. For a dependency finding it can edit that project's manifest, and the lockfile is regenerated. A fix that would belong in a file the pull request didn't touch, or that needs a new file or dependency, isn't made; the finding is listed under Could not fix with the reason.
Each attempt is rescanned; one the rescan doesn't verify is rolled back, and the next attempt starts from the original code with that outcome as context. After the last attempt a finding that is still reported keeps its original code and is listed under Could not fix, with the reason: the attempts ran out, the agent judged it a false positive and says where the value becomes safe, the change strayed outside the finding, the lockfile couldn't be regenerated, or the rescan didn't complete.
What gets published
A completed run publishes:
- A status comment that opens with a one-sentence headline, lists every finding under exactly one heading, and ends with a count line, such as
1 fix, 2 remaining, 1 ignored, 3 iterations. The headings are Fixed, No automatic fix, Could not fix, Ignored (a Snyk Code finding the connected Snyk organization has an accepted, unexpired ignore for, shown with its reason), Not scanned, and Warnings (files the scanner couldn't fully parse). Line numbers refer to the pull request head before any fix commit. - A fix commit on the branch in Fix mode, or a review with suggestions in Advisory mode. Fixes that verified are published whatever else the run found.
- A check run,
Tessl Vulnerability Remediation, on the fix commit when the run pushed one, and otherwise on the head it scanned:
A clean result names the scanner and says it found no vulnerabilities in the changes it scanned. A scanner reports what its rules match; it's not a security review.
The check holds a merge only when your branch protection or ruleset requires it. Leave that off and every result stays informational.
Limits
- Attempts. Each finding gets up to 10 fix attempts by default. Change it, from 1 to 100, with the repository's Maximum iterations.
- Runs per pull request. The repository's Maximum rounds setting (default 3) caps how many fix runs a pull request can have in total, so remediation and review can't keep changing the same code back and forth. A request past it gets a reply saying so.
- Runs per hour. At most six fix runs per pull request per hour.
- Time. A run stops starting new attempts after 50 minutes and ends with the fixes it has. A run that hasn't finished 90 minutes after it was requested is reported as failed.
- Moved head. A run only publishes onto the head it scanned. If the branch moved while a run or a scan was going, nothing is published, the check fails with that reason, and the status comment shows only that failure, with no findings. Comment again to run on the new head.
Scans count toward none of the run limits.
Permissions the App holds
Vulnerability Remediation uses the permissions the App already requests for Code Review, listed in Set up Tessl Code Review. Turning it on doesn't ask for new permissions. Each run uses tokens minted for that run and scoped to the single repository.