What this guide covers
How do I run DerTriage on individual SAST findings instead of the whole scan, and drive DerScanner over the API with a token?
Selective verification runs DerTriage against findings you choose, one at a time, from the actions menu of an individual finding. It is a different workload from scan-wide triage, which verifies every finding of the selected severities as part of the scan.
Scan-wide triage is the workload to plan GPU capacity for. Selective verification of a handful of findings is practical on a CPU-only host, which makes it the sensible mode for local installations and for spot-checking a small number of results.
Everything in this guide is done over the DerScanner REST API with a named token and in the web interface. DerScanner also publishes an IDE extension, but no extension is required to drive a scan or to verify a finding.
Before you start
- A DerScanner installation you can reach over HTTP, and an administrator account that can create users.
- A user account for this work that is not the administrator account. The screenshots in this guide were taken under a dedicated non-administrator account.
- A source archive to scan. This guide uses a synthetic application described in step 3.
- curl, or any HTTP client that can send multipart form data.
Environment
- DerScanner deployment
- Self-hosted installation, single host, reached at an internal URL. Replace the host in every command with your own.
- DerTriage runtime
- Local DerAI service on the same host, CPU only, no GPU present.
- Scan target
- Synthetic Delphi application, about 8,000 lines across 23 source files, written specifically for this guide.
- Account used for screenshots
- Dedicated non-administrator account with scan quotas raised for the evaluation period.
The walkthrough
Step 1
Create a dedicated account for the work
Keep evaluation work, API tokens, and screenshots out of the administrator account.
An administrator account sees every project on the installation and carries permissions that automation does not need. Create a separate user for this work, give it a non-administrative role, and use it for the scan, the token, and the interface.
The account used throughout this guide is a regular user with full access to product functions and no administrative panel. Scan quotas were raised for the evaluation period so that repeated scans would not exhaust a limit mid-guide.
Sign in as that user before continuing. The first sign-in asks the account to accept the end user licence agreement.
Step 2
Issue an API token
Drive DerScanner from a script without installing anything into the IDE.
DerScanner publishes an IDE extension for SAST and SCA, and it is a reasonable way to work if you live in the editor. It is not a prerequisite for anything below. A named API token gives the same control from a shell, a pipeline, or any HTTP client.
Request a token with the account credentials and a name you will recognise later. The name matters because tokens are listed and revoked by name.
The response contains an access token. Send it as a bearer token on every subsequent request. Treat it as a credential — it carries the permissions of the account that issued it, so keep it in a secret manager rather than in a shell history or a repository.
curl -s -X POST "https://derscanner.example.com/app/api/v1/auth/jwt" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "username=$DERSCANNER_USER" \
--data-urlencode "password=$DERSCANNER_PASSWORD" \
--data-urlencode "token_name=guide-api"
# {"accessToken":"eyJhbGciOiJIUzUxMiJ9..."}Step 3
Prepare a target whose ground truth you know
Make it possible to judge the verification result rather than trust it.
A verification feature can only be assessed against code whose defects you already know. This guide therefore uses a synthetic application, written for this purpose and for no other. It is not a real product, it was never deployed, and it is not an open-source project belonging to anyone else.
The application is a Delphi warehouse operations tool of about 8,000 lines across 23 units — a login form, an inventory module, orders, suppliers, reporting, backup, and a data access layer. It contains deliberate defects, including SQL statements assembled by string concatenation from values the operator types into the interface.
Package the source as a zip archive. The scan in the next step uploads that archive directly, so nothing needs to be checked into a repository the scanner can reach.
Step 4
Start a scan with scan-wide AI triage switched off
Keep the scan fast and leave verification as a deliberate, separate decision.
Scan settings include AI triage per severity, plus an option to apply the triage result to the finding status automatically. When those are on, every finding of the selected severities is verified as part of the scan. That is the workload to size GPU capacity for, and it is the workload to avoid on a CPU-only host.
Start the scan with those flags explicitly off. The scan then does what a scan does — analyse the code — and leaves every finding unverified for you to choose from.
The response returns the scan identifier you will poll in the next step.
TOKEN="$DERSCANNER_TOKEN"
PROJECT="4272a7c0-febb-4ee3-a249-2b72bfe8022c"
curl -s -X POST "https://derscanner.example.com/app/api/v1/scan/start" \
-H "Authorization: Bearer $TOKEN" \
-F "file=@warehouse-ops-delphi.zip" \
-F "uuid=$PROJECT" \
-F "languages=CS,CCPP,JAVA,JAVASCRIPT,PASCAL,PHP,PYTHON,REGEX,TSX,TYPESCRIPT" \
-F "aiTriageCritical=false" \
-F "aiTriageMedium=false" \
-F "aiTriageLow=false" \
-F "aiTriageInfo=false" \
-F "applyTriage=false"
# {"projUuid":"4272a7c0-...","scanUuid":"4331e444-..."}Step 5
Poll the scan and list what it found
Get to a specific finding identifier you can act on.
Poll the project's scan list until the scan reports COMPLETE. The same record carries the severity counts, so a single request tells you both that the scan finished and how much it found.
This scan reported 65,272 lines of code and two critical findings, both SQL injection. Findings are grouped by the rule that produced them, so a second request returns the rule names with the number of findings under each.
Resolve an individual finding identifier to its position in the source. The response gives the file and line along with the current verification status, which is where the DerTriage verdict will appear later.
curl -s "https://derscanner.example.com/app/api/v1/projects/$PROJECT/scans?offset=0&limit=5" \
-H "Authorization: Bearer $TOKEN"
curl -s "https://derscanner.example.com/app/api/v1/scans/$SCAN/issuesGroupedByRules?offset=0&limit=50" \
-H "Authorization: Bearer $TOKEN"
# {"SQL injection":2}
curl -s -X POST "https://derscanner.example.com/app/api/v1/issues/sources" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "[\"$ISSUE_ID\"]"
# [{"name":"warehouse-ops-delphi/src/uOrders.pas:558","verification":"NOT_PROCESSED"}]Step 6
Read the code before asking anything to verify it
Form your own judgement first, so the verdict has something to be checked against.
Open the finding in the interface. The code panel highlights the flagged line together with the surrounding function, which is usually enough to decide whether the data reaching the sink is attacker-controlled.
In this finding the order reference is a string parameter that is concatenated into a SQL statement inside single quotes, with no parameterisation and no escaping. The caller passes the order number the operator selected in the grid or typed into the quick filter, so the value is operator-controlled by design.
That is a genuine injection, and knowing it independently is what makes the next step meaningful.
function TOrderService.LoadOrder(const AOrderRef: string;
var AOrder: TOrderRecord): Boolean;
var
Query: TADOQuery;
begin
Result := False;
Query := FDatabase.OpenDataSet('SELECT * FROM orders WHERE number = ''' + AOrderRef + '''');Step 7
Run DerTriage on that one finding
Verify a specific result without starting a scan-wide verification job.
Selective verification is started from the actions menu of an individual finding — the three dots at the right-hand end of the finding row. This is the row that names the file and line, not the row that names the rule and carries the count. Opening the menu on the group row gives you bulk status editing instead.
The menu contains a DerTriage button below the comment field. Pressing it queues verification for that finding alone. The button is replaced by a progress indicator while the job runs, and the verdict appears in the same menu when it completes.
This is the mode that makes local, CPU-only installations useful. One finding is a small job, so a CPU host can return a verdict in a reasonable time, while verifying an entire scan the same way is not a workload to plan without a GPU.
Step 8
Read the verdict and decide
Treat the output as a recommendation that you accept or reject.
The verdict is written into the finding's menu as plain text. For this finding DerTriage reported that the SQL query is constructed by directly concatenating user input, named the parameter it followed, and recommended a status.
The recommendation matches the reading of the code from the previous step — the same parameter, the same mechanism. That agreement is the point of the exercise. Press Apply to record the status on the finding, or set a different status if you disagree.
The verdict names `AOrderRef`, which is the parameter on the flagged line. A verdict that discusses a parameter you cannot find in the code is a signal to look at what context the analyzer actually supplied, not a reason to accept the status.
DerTriage: The SQL query is constructed by directly concatenating user
input (`AOrderRef`) into a string variable, which can be exploited to
execute malicious SQL commands. DerTriage recommends changing the
vulnerability status to Confirmed.Checking your result
How do I know the scan really ran without scan-wide triage?
The scan never enters a triage step. A scan with AI triage enabled reports a second step and a triage progress percentage in the scan list; a scan started with the flags off goes straight to COMPLETE, and every finding stays at NOT_PROCESSED until you verify it yourself.
How do I know the verdict belongs to the finding I selected?
The verdict names the identifier from the flagged line — in this walkthrough, the parameter concatenated into the statement. Verification was queued for one finding, so the other finding in the same group remains unverified, which is visible in its status.
How do I confirm the token works before starting a scan?
Request the project's scan list with the bearer token. A 200 response with the scan array confirms both the token and the account's access to that project. A 401 with "No token" means the header never reached the API.
Limits of this procedure
- DerTriage returns a recommendation, not a proof. It recommends a status; the engineer decides. Verdicts on the same scan can disagree with the code, including recommending rejection for a finding that is genuinely exploitable, so a verdict is a second opinion to weigh against your own reading rather than a substitute for it.
- The verdict is formed from the code supplied as context for the finding. Where the untrusted value enters in a different unit from the sink, the reasoning is based on the local snippet and may not describe the full data path.
- Verification time is a property of the host, not of the feature. A memory-constrained DerAI service slows verdicts down by orders of magnitude, and a queued job blocks the ones behind it.
- Selective verification and scan-wide verification are different workloads. Conclusions about the practicality of one say nothing about the other.
- The target here is synthetic. It demonstrates the workflow and the shape of the output; it does not indicate detection or verification quality on production code.
Related knowledge
Canonical terms used: DerTriage; selective verification; SAST finding; true positive; vulnerability status.
DerScanner