Vornin handbook.
Everything you need to know about using Vornin to secure your infrastructure — from onboarding to the REST API.
Vornin Documentation
Everything you need to know about using Vornin to secure your infrastructure.
Overview
Vornin is a vulnerability management platform that helps you find, track, and fix security issues across your servers, websites, and code. It combines 15 scanner engines into a single dashboard with compliance mapping (DORA, NIS2, and seven other frameworks), SLA enforcement, a tamper-evident evidence chain, and team collaboration.
First Steps
- Sign in — You'll receive a magic link email. Click it to sign in (no password needed).
- Complete onboarding — The wizard walks you through adding your first target, configuring branding, SLA policies, and notifications.
- Add targets — Add the domains, IPs, or internal hosts you want to scan.
- Run a scan — Select your targets and scan types, then launch.
- Review results — Vulnerabilities appear in your dashboard with severity ratings, remediation guidance, and compliance mappings.
Onboarding Wizard
When you first log in, the onboarding wizard walks you through the minimum setup needed to get a useful scan running:
- Add a Target — Enter a domain or IP address.
- Run Your First Scan — A quick scan with port scanning, SSL/TLS, and DNS security.
- Branding (optional) — Set your company name, website, report title, and brand color for white-label reports.
- SLA Policies (optional) — Define remediation deadlines per severity (e.g., Critical = 1 day, High = 7 days).
- Notifications (optional) — Enable email reminders and set escalation contacts.
All settings can be changed later under Configuration.
Managing Targets
Targets are the hosts you want to scan — domains, IP addresses, or internal servers.
Adding Targets
- Go to Targets and click Add Target.
- Enter a name, host (domain or IP), and optional description.
- Assign to a group for organization (e.g., "Production", "Staging").
- Assign a scan agent if the target is on an internal/private network.
Target Kinds
Every Target has a Kind that controls which scanners can run against it:
- Hostname — vhost/SNI-aware scans (Web/API use the
Hostheader; subdomain enumeration allowed). - IP Address — whole-IP scans (PortScan, SSL/TLS, Nuclei). Web scanners use the default vhost.
- IP Range (CIDR) — expanded to per-IP PortScan tasks. CIDR capped at
/16. - URL — preserves path and port for Web scanners targeting a specific app endpoint.
Vornin auto-detects the Kind from the Host string; you can override it before saving. Once a scan has run against a Target, the Kind is locked — create a new Target if you need different scan semantics.
If a Target's IP belongs to a CDN range or its TLS certificate covers many unrelated brands, Vornin shows a Shared infrastructure warning. Findings on shared infra may not be yours to remediate — confirm ownership before action. Dismiss the warning from the Target's edit dialog if it's a legitimate multi-brand cert under your control.
CSV Import
Bulk-import targets from a CSV file. The CSV should have a Domain column header, one domain per row.
Target Groups
Groups let you organize targets and scan them together. Create groups with custom colors for visual identification.
Scan Types
Fifteen native engines are available. Most run fully automatically once you've added a target; only Web / API (authenticated mode), the code-repo scanners, and the cloud / Kubernetes scanners (which need credentials) require extra configuration, covered in their own sections below.
| Scanner | What It Checks | Requirements / Tool |
|---|---|---|
| Port Scan (TCP + UDP) | Open ports, running services, service versions. TCP top-1000 ports by default (Quick / Standard / Thorough preset configurable per scan); UDP top-100 ports when Nmap is available. Scans on hosts without Nmap fall back to a TCP-connect scan and surface a clear "Limited port scan" notice. | Nmap (recommended — required for UDP + service-version detection) |
| SSL/TLS Security | Certificate validity, protocol versions, cipher suites, weak signature algorithms, weak key sizes, HSTS — plus protocol-level vulnerabilities via SSLyze: Heartbleed (CVE-2014-0160), ROBOT (CVE-2017-13099), OpenSSL CCS Injection (CVE-2014-0224), insecure renegotiation, CRIME / TLS compression, fallback-SCSV. | None for the core checks; Docker on the scanner host enables the SSLyze augmentation |
| Web Vulnerability | Backed by OWASP ZAP baseline (passive scan + AJAX spider for SPA crawling) plus our curated path-probe library (~70 sensitive paths: .git, .env, backup files, admin panels, server-status, …), security header and cookie checks, CORS, HTTP methods, HTTPS-redirect behavior, and outdated JS library detection. Opt into Active attack probes on the ScanNow page to run ZAP’s full active scan (SQLi, XSS, LFI, command injection payloads) against non-production targets. Supports authenticated scanning (cookie, bearer token, basic auth). | Docker (bundled on the scanner host; agents fall back to curated checks only) |
| API Security | CORS misconfiguration, authentication bypass, verbose error disclosure, endpoint discovery, rate limiting, API doc exposure. Optionally provide an OpenAPI / Swagger spec URL in Settings → Scanning to additionally run OWASP ZAP's API scan against the spec. | None for the behavioural probes; Docker on the scanner host enables the optional ZAP API scan |
| Nuclei Templates (opt-in) | Thousands of community-maintained templates for CVEs, misconfigurations, and technology signatures | Nuclei binary on PATH (agent or server) |
| DNS Security | SPF, DKIM, DMARC, DNSSEC, CAA (issuance pinning), MTA-STS (TXT signal + .well-known/mta-sts.txt policy file), and AXFR (zone-transfer attempt against your authoritative name servers). | None |
| Subdomain Discovery | Finds subdomains via DNS brute-force, certificate-transparency logs (crt.sh), and 45+ passive sources via Subfinder (search engines, threat-intel feeds, third-party APIs). Wildcard-DNS suppression and live-resolution filtering applied across all sources. | None for DNS + crt.sh; Docker on the scanner host enables Subfinder's broader passive sources |
| SAST (Static Analysis) | Code vulnerabilities via Semgrep, with three layered rule packs: language-specific auto-detect, OWASP Top 10, and CWE Top 25. | Code repository connected; Semgrep CLI on PATH |
| Secret Scanning | Leaked credentials, API keys, tokens via Gitleaks. Severity is calibrated per rule type — private keys + cloud root credentials are Critical, named provider tokens are High, generic high-entropy strings are Medium. Configure a per-tenant .gitleaksignore in Settings → Scanning to suppress known false positives (e.g. test fixtures with synthetic credentials). | Code repository connected; Gitleaks CLI on PATH |
| Dependency Scanning | Known CVEs in third-party dependencies via Trivy. Findings carry a Reachability tag (Reached / Unreached / Unknown) so you can deprioritise vulns in packages that aren't actually called from your code. Optional "Hide CVEs without an available patch" toggle in Settings → Scanning filters out unfixable findings so the queue only contains actionable work. | Code repository connected; Trivy CLI on PATH |
| Container Image Scanning | OS + language-package CVE scanning of container images via Trivy. Configure registry credentials in Settings → Scanning to scan private images; public Docker Hub / GHCR images need no credentials. Layered-image awareness so a CVE in a shared base layer isn't double-counted across the apps that inherit it. | Docker on the scanner host; Trivy CLI on PATH |
| Kubernetes Posture | Cluster misconfiguration scanning against Pod Security Standards and CIS Kubernetes Benchmark. Detects privileged containers, hostPath mounts, missing resource limits, default-namespace workloads, weak network policies, and exposed kube-apiserver / etcd endpoints. Requires a read-only kubeconfig connected via Cloud Connections; the credential never leaves the encrypted database column. | Connected Kubernetes cluster (kubeconfig with read-only RBAC) |
| Cloud Posture (AWS / Azure / GCP) | Cloud-configuration scanning against CIS Benchmarks for each provider: public S3 buckets, overly permissive IAM, unencrypted EBS / managed disks, default-VPC exposure, missing CloudTrail / Activity Log, public Lambda / Function App URLs, RDS / Cloud SQL public-access flags, and more. Connect an AWS IAM role / Azure service principal / GCP service account with read-only audit-tier permissions via Cloud Connections. | Connected cloud account (read-only audit-tier credentials) |
| Subdomain Takeover | Detects dangling DNS records pointing at unclaimed cloud-provider hostnames (S3 buckets, Azure App Services, Heroku apps, GitHub Pages, Fastly, Netlify, etc.) where an attacker can claim the destination and serve content under your subdomain. Runs after Subdomain Discovery so every newly-discovered host is automatically evaluated. | None |
| WordPress Security | WordPress-specific vulnerability scanning via WPScan: outdated core, plugin and theme versions matched against the WPScan vulnerability database, exposed admin endpoints (xmlrpc, wp-cron, user enumeration), and weak credentials. Configure an API token in Settings → Scanning to unlock the full WPScan vuln feed; without a token the scanner reports version-only findings. | Docker on the scanner host; optional WPScan API token (free tier available) |
When a required CLI binary is missing at scan time, Vornin surfaces a Low-severity "Scanner Unavailable" finding instead of silently producing a clean report. Install the binary (or route the scan to an agent that has it) to re-run and clear the finding.
Reachability Analysis
Every dependency finding is tagged with one of three reachability states. The goal is to answer a simple question: does the vulnerable package actually end up in your call tree, or is it sitting in a lockfile no one ever calls? Industry benchmarks suggest 30–50% of dependency findings are "unreached" — tagging them lets you focus remediation where real risk lives.
| State | What it means | How to treat it |
|---|---|---|
| Reached | The vulnerable package is imported from at least one first-party source file that isn't a test. The vulnerability lives in code your app can actually hit. | Treat as real risk. Prioritise by severity + exploit signal. |
| Unreached | The package is either not imported anywhere in your source tree, or only imported from test/spec files. A transitive dependency that shipped but is never called. | Safe to deprioritise in triage. Still worth an eventual upgrade for supply-chain hygiene. |
| Unknown | Analysis hasn't been performed yet — the finding was created before the analyser ran, your tenant has the kill switch enabled, or the repo had no supported source files to analyse (JS/TS, Python, Go, Java, C#). | Expected during rollout. Re-run the scan and most findings will resolve to Reached or Unreached. |
How it works
Vornin uses an import-usage heuristic, not a full call-graph. For each finding Trivy produces, the analyser walks your cloned repository, builds a per-language index of imported package names, and checks whether the vulnerable package appears in any non-test source file. Import parsing is language-aware:
- JS/TS —
import … from 'pkg'andrequire('pkg'). Scoped packages (@scope/pkg) and sub-paths are resolved to their root. - Python —
import pkgandfrom pkg import …. Submodule imports match the root package. - Go — grouped and single-line
import "github.com/…"statements. Matched as module-path prefix so sub-paths likegin/bindingstill resolve togithub.com/gin-gonic/gin. - Java —
import org.apache.…matched against the TrivygroupIdas a dotted-path prefix. - C# —
using Newtonsoft.Json;matched against the NuGet package id as a dotted-path prefix.
Test files are detected by path segment (test/, tests/, __tests__/, spec/) and filename conventions (*.test.*, *.spec.*, *_test.go, test_*.py, *Test.java, *Tests.cs). Build outputs and vendored code (node_modules, vendor, bin, obj, dist, build, target) are excluded so a package imported only inside node_modules doesn't falsely read as Reached.
Known limitations
This is a pragmatic heuristic, not exploit-path analysis. Situations where it's conservative (leans towards Reached):
- A package you import but never actually call will still read as Reached — import-presence, not invocation.
- Ambiguous Java
groupIdor C# namespace prefixes are treated as matches. False positives favour visibility. - Dynamic dispatch, reflection, and plugin loaders are invisible to static import parsing — a plugin-loaded vulnerable package will read as Unreached even if it runs at runtime.
The Reachability state refreshes on every scan. A finding never regresses from a known state (Reached or Unreached) back to Unknown — if a later scan can't compute the state (analyser skipped, repo deleted), the previous signal is preserved.
Filtering and API access
The Vulnerabilities page in the app has a Reachability filter alongside severity and status. The REST API returns reachability as a string on every vulnerability, and the vulnerability.found webhook includes the same field — downstream automation can route Unreached findings to a lower-priority channel.
Tenant kill switch
If you don't want the extra walk on every dependency scan, set DisableReachabilityAnalysis = true on the tenant's ScanSettings. All findings will stay Unknown until you re-enable it.
Running Scans
Go to Scan Now to start a scan. The 3-step wizard lets you:
- Select Targets — Pick individual targets, groups, or code repositories.
- Choose Scanners — Select which scan types to run. Choose "Full Scan" for all applicable scanners.
- Review & Launch — Name your scan and launch it.
Tip: Private/internal IP targets (192.168.x.x, 10.x.x.x, etc.) require a scan agent installed on the internal network. Vornin will never scan private networks directly from the cloud for security reasons.
Authenticated Scanning
Scan behind login pages by providing credentials in Step 2 of the Scan Now wizard. Expand the "Authenticated Scanning" panel and choose a method:
- Session Cookie — paste the Cookie header from your browser dev tools
- Bearer Token — provide a JWT or API token
- Basic Auth — enter username and password
Authenticated scans find significantly more vulnerabilities than unauthenticated scans because they can access protected pages and API endpoints.
Attack Surface Discovery
When a Subdomain Enumeration scan runs, discovered subdomains are added to the Attack Surface inbox (Scanning → Attack Surface) instead of immediately triggering additional scans. Each found subdomain appears with its source, IP addresses, and first/last seen timestamps.
From the inbox you can Add as Target to promote a subdomain for a focused follow-up scan, or Ignore to suppress it from the active view. Status never regresses — re-discovering an Ignored subdomain keeps it ignored and only refreshes its metadata. Vornin also monitors your attack surface daily and sends an in-app notification when new assets appear for your registered domains.
Scheduled Scans
Set up recurring scans under Schedules. Configure the targets, scan types, and schedule (daily, weekly, monthly). Scheduled scans run automatically and results appear in your dashboard.
Attack Surface
Every scan you run automatically populates a tenant-scoped Attack Surface
inventory: hosts, IPs and open services, TLS certificates (deduplicated
by SHA-256 fingerprint), DNS posture (SPF / DMARC / DKIM / CAA),
and detected technology versions. Each entity type has its own sub-page
under /attack-surface with KPIs, filters, and staleness chips.
Inventory is forward-only — rows hydrate from the next scan after the
feature is enabled and persist through subsequent scans. A row stops
appearing in the default "Active (30d)" filter once its LastSeenAt
is older than 30 days; switch to "All" to see stale entries.
Code Scanning
Connect your GitHub or Azure DevOps repositories under Repositories:
- Add a Connection — Enter your GitHub or Azure DevOps PAT (Personal Access Token).
- Import Repositories — Select repositories and the branch to scan.
- Scan — Include repositories in your scans from the Scan Now page. Code scanners (SAST, Secret, Dependency) will analyze the selected branch.
Scan Agent Overview
The Vornin Scan Agent is a lightweight application you install on your internal network. It allows Vornin to scan internal/private targets that aren't accessible from the internet.
The agent:
- Runs on Windows or Linux (x64 and ARM64)
- Connects outbound to Vornin (no inbound ports needed)
- Receives scan tasks, executes them locally, and reports results back
- Includes port scanning, SSL/TLS, DNS, web vulnerability, and subdomain scanners
Agent Installation
The agent is a framework-dependent .NET 9 binary. Install the .NET 9 runtime for your platform first if it isn't already present.
Step-by-step: register and run the agent
- Sign in to Vornin and go to Admin → Scan Agents.
- Click Register Agent, give it a name (e.g. branch-office-01), and click Create.
- Copy the generated agent key (starts with
cva_). It is shown only once — if you lose it, you can regenerate from the same page. - Download the agent binary for your platform from the Downloads page (Windows x64, Linux x64, or Linux ARM64).
- Run the agent on the target machine — see the platform-specific commands below.
- Paste the agent key when prompted. The agent connects outbound to
https://app.vornin.com— no inbound ports need to be opened. - Back in Admin → Scan Agents, confirm the agent shows as Online.
Windows (foreground)
vornin-agent-win-x64.exe
To run as a Windows Service, use sc.exe create or NSSM. See the Service Control Manager reference.
Linux (systemd)
chmod +x vornin-agent-linux-x64
sudo mv vornin-agent-linux-x64 /usr/local/bin/vornin-agent
sudo tee /etc/systemd/system/vornin-agent.service <<'UNIT'
[Unit]
Description=Vornin Scan Agent
After=network-online.target
[Service]
ExecStart=/usr/local/bin/vornin-agent
Environment=VORNIN_AGENT_KEY=cva_your_key_here
Restart=on-failure
User=vornin
[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl daemon-reload
sudo systemctl enable --now vornin-agent
Agent Configuration
The agent connects to https://app.vornin.com automatically. You can supply the agent key non-interactively instead of being prompted on first run:
| Setting | Environment Variable | CLI Argument | Default |
|---|---|---|---|
| Agent Key | VORNIN_AGENT_KEY | --key=KEY | Prompted on first run |
The agent saves the key locally so you only need to provide it once. To change the key later, run vornin-agent --reset-key.
Nmap (optional, recommended): For UDP scans and richer port/service detection, install Nmap on the agent host:
- Windows — download the installer from nmap.org/download and run it.
- Debian / Ubuntu —
sudo apt-get install nmap - RHEL / Fedora —
sudo dnf install nmap - Alpine —
apk add nmap
Without Nmap, the agent falls back to a basic TCP-connect scanner (TCP only, service versions limited).
Scanning with Agents
Targets are automatically routed to agents when:
- The target has a scan agent assigned in its settings, OR
- The target's host is a private/internal IP address (RFC 1918)
To assign an agent to a target: edit the target and select the agent from the dropdown. The agent's online/offline status is shown in the Targets list.
Vulnerability Dashboard
The Vulnerabilities page shows all discovered security issues across your targets. Each vulnerability includes:
- Severity — Critical, High, Medium, Low, or Info
- Status — Open, Acknowledged, Resolved, or Dismissed
- Affected host and port/service
- Description and Solution guidance
- CVE ID and CVSS score (when available)
- First/Last detected timestamps
- SLA deadline and SLA state column (Breached / Due soon / OK / N/A) — sortable and filterable if SLA policies are configured
Vulnerability Lifecycle
| Status | Meaning | Transitions |
|---|---|---|
| Open | Detected and needs attention | → Acknowledged, Dismissed, Resolved |
| Acknowledged | Team is aware, working on it | → Resolved, Dismissed, Open |
| Dismissed | Accepted risk or false positive | → Open |
| Resolved | Fixed (auto-detected when finding disappears from subsequent scan) | → Open (if redetected) |
Auto-resolve: When a subsequent scan no longer detects a previously open vulnerability, it's automatically marked as Resolved.
Auto-reopen: If a resolved vulnerability reappears in a later scan, it's automatically reopened.
Suppression Rules
Suppression rules automatically dismiss future detections that match specific criteria. Create rules from:
- The vulnerability row — click the suppress icon to create a rule pre-filled with that vulnerability's details.
- The Accept Risk dialog — check "Create suppression rule for future scans".
- Admin → Suppression Rules — manage all rules centrally.
Rules can match by fingerprint (exact), title pattern (contains), host pattern (exact or wildcard), or scanner type.
SLA Policies
SLA policies define how quickly vulnerabilities must be remediated. Configure per severity level under Configuration → SLA Policies:
| Severity | Default Remediation | Escalation |
|---|---|---|
| Critical | 1 day | Immediate |
| High | 7 days | 5 days |
| Medium | 30 days | 25 days |
| Low | 90 days | 80 days |
When a vulnerability exceeds its SLA deadline, escalation emails are sent to the configured contacts. If no escalation contacts are configured on a policy, notifications automatically fall back to the tenant's Owner(s).
Policy changes backfill immediately. When you change a severity's Remediation days, every open or acknowledged vulnerability at that severity has its SLA due date recomputed on save — you do not need to wait for the next scan.
SLA state in the Vulnerabilities list. The Vulnerabilities page shows an SLA column with one of four states:
- Breached — past the SLA deadline
- Due soon — within 3 days of the deadline
- OK — within SLA
- N/A — no SLA policy applies (e.g., resolved, dismissed, or no policy configured for that severity)
The column is sortable, and the list has a dedicated filter for Breached only, Due soon, and Without SLA. The vulnerability detail page shows a live countdown chip ("Due in 2d 4h", "Breached 3d ago") in the same color coding.
MTTR & SLA Metrics
The Executive Dashboard surfaces two related metrics:
- MTTR (30-day rolling) — mean time to remediate, in days, averaged across all vulnerabilities resolved in the last 30 days. Computed from the
ResolvedAttimestamp set when a vulnerability transitions to Resolved. The dashboard shows an overall value and a collapsible per-severity breakdown (Critical / High / Medium / Low). Empty cohorts render as "–" rather than "0". - SLA Compliance — percentage of vulnerabilities inside SLA at snapshot time. Shown both as an overall figure and as a per-severity breakdown with progress bars — so you can see at a glance whether Critical compliance is slipping even if the overall number looks healthy.
Both metrics are computed nightly by the daily snapshot job and stored per tenant, so trends over time are preserved even after vulnerabilities are resolved or deleted. Vulnerabilities that were already resolved before the ResolvedAt timestamp was introduced are excluded from MTTR (they have no recorded resolution time).
Reports
Vornin generates audit-ready PDF vulnerability reports containing:
- Executive summary with risk score and grade
- Vulnerability breakdown by severity
- Detailed findings with remediation guidance
- Your company branding (logo, colors, footer text) — see Report Branding
Step-by-step: generate a report
- Go to Reports.
- Pick the target or target group and the severity filter (e.g. High + Critical only).
- Choose the report template (Executive, Technical, or Compliance).
- Click Generate. The PDF is produced via QuestPDF and downloads when ready.
Step-by-step: schedule recurring reports
- Go to Report Schedules → New Schedule.
- Configure the target filter, template, cadence (daily / weekly / monthly), and recipient email list.
- Save. Each scheduled run emails the PDF to the configured recipients automatically.
Compliance
The Compliance dashboard maps your vulnerabilities to industry compliance frameworks:
- CIS Controls v8 — Center for Internet Security
- NIST 800-53 Rev 5 — National Institute of Standards and Technology
- ISO 27001:2022 — Information Security Management
- SOC 2 Type II — Trust Services Criteria
- PCI DSS 4.0 — Payment Card Industry Data Security Standard
- HIPAA — Health Insurance Portability and Accountability Act
- GDPR — General Data Protection Regulation
- DORA — Digital Operational Resilience Act (EU 2022/2554)
- NIS2 — Network and Information Security 2 (EU 2022/2555)
Vulnerabilities are automatically mapped to specific controls in each framework based on the scanner type and severity. Compliance scores update in real-time as vulnerabilities are found and resolved. Download audit-ready PDF compliance reports.
Each framework has its own page at /admin/compliance/<slug> with three things the index page doesn't show:
- Per-control drill-down. Click any failing control to see exactly which open findings caused it to fail — severity, asset, scanner, first-seen date, SLA status — each row links straight to the underlying vulnerability.
- 90-day score trend. A line chart of the framework score over the last 90 days. Daily snapshots are written by the background snapshot service, so the trend grows from your first run forward (no retroactive backfill).
- Mapping transparency. A panel that lists exactly which control IDs every Vornin scanner contributes to that framework — so auditors and prospects can see the algorithm rather than trust a black box.
Executive View
The Executive View provides a high-level risk overview designed for management and stakeholders: risk scores, severity distribution, top-5 risky targets, month-over-month comparisons, 90-day trends, and per-severity SLA compliance and MTTR (30-day rolling) — everything leadership needs without technical detail. See MTTR & SLA Metrics for how these values are computed.
Report Branding
Customize your reports under Configuration → Report Branding:
- Company name and website
- Report title and footer text
- Company logo (PNG/JPG, max 2MB)
- Primary brand color
Notifications
Enable email reminders for open vulnerabilities under Configuration → Notifications. Set the reminder interval (e.g., every 7 days). Team members with assigned vulnerabilities will receive periodic email reminders.
Per-scan completion emails
Both the Scan Now wizard and the scheduled-scan dialog expose an "Email when this scan completes" toggle. When enabled, a Send to field appears — it is prefilled with your account's email address and accepts any number of additional recipients separated by ; or , (up to 10 per scan). The same options are accepted by the API: include notifyOnCompletion and notifyEmails in the body of POST /v1/scans. Each recipient receives a one-page HTML summary with severity counts, scan duration, and a direct link to the scan. Failed scans are emailed too, with a red Failed status pill and the error message inline; cancelled scans are silent because they are user-initiated.
User Management
Manage your team under Admin → Users. Roles:
| Role | Permissions |
|---|---|
| Owner | Full access including billing, user management, and tenant settings |
| Admin | Manage scans, targets, users, suppression rules, and configuration |
| Member | View dashboards, run scans, manage assigned vulnerabilities |
Invite users via email from the Users page. They'll receive an invitation link to join your workspace.
Single Sign-On (SSO)
Vornin supports Microsoft Entra ID (formerly Azure AD) for SSO via a one-click admin-consent flow — you do not need to create or paste any client secrets. Once connected, users from your Azure tenant can sign in with their existing corporate account.
Step-by-step: connect Entra ID
- Sign in to Vornin as an Owner or Admin of your tenant.
- Go to Settings → Single Sign-On (SSO).
- Click Connect with Entra ID. You'll be redirected to Microsoft for admin consent.
- Sign in to Microsoft with an account that is a Global Administrator (or has the Privileged Role Administrator / Cloud Application Administrator role) of your Azure tenant. See Microsoft Entra built-in roles.
- Review the requested permissions and click Accept on the Microsoft consent screen. Microsoft will redirect you back to Vornin.
- Confirm the green "Connected to Microsoft Entra ID (Tenant: your-tenant-id)" banner on the SSO page.
- Share the tenant login URL with your users:
https://app.vornin.com/auth/entra/login?tenantSlug=<your-slug>.
Background reading: Register an application with Microsoft Entra ID, Admin consent on the Microsoft identity platform, and OpenID Connect on the Microsoft identity platform. Vornin's Entra integration is OIDC-based — the SAML protocol is not required.
Disconnecting Entra ID
From Settings → Single Sign-On (SSO), click Disconnect Entra ID. Users lose the ability to sign in via Microsoft but their Vornin accounts, magic-link access, and TOTP enrolment remain unchanged. You can reconnect at any time.
Step-by-step: SAML 2.0
Vornin is a fully featured SAML 2.0 service provider. Each tenant gets its own per-tenant SP entity ID, ACS URL, and metadata URL. Bring any IdP that speaks SAML 2.0 — Okta, Microsoft Entra ID (SAML app), Google Workspace, PingFederate, JumpCloud, OneLogin.
The flow is the same on every IdP: copy Vornin's three SP URLs from Settings → SAML 2.0 SSO into the IdP's SP form, paste the IdP's entity ID + SSO URL + signing certificate back into Vornin, then enable. Detailed walkthroughs:
Okta
- In Okta admin: Applications → Create App Integration → SAML 2.0 → Next.
- App name Vornin. On the SAML Settings page paste the SP ACS URL from Vornin Settings into "Single sign-on URL" and the SP Entity ID into "Audience URI (SP Entity ID)".
- Set Name ID format to EmailAddress and Application username to Email.
- Save. Open the new app's Sign On tab → View Setup Instructions. Copy the Identity Provider Issuer, Identity Provider Single Sign-On URL, and the X.509 Certificate.
- In Vornin Settings → SAML 2.0 SSO, paste those three values into IdP Entity ID, IdP SSO URL, and IdP X.509 Signing Certificate. Toggle Enable SAML SSO and click Save.
- Click Test SSO. The IdP login page opens; sign in with an Okta user that already has a Vornin invitation accepted.
Microsoft Entra ID (SAML application)
- In Entra: Enterprise applications → New application → Create your own application. Name it Vornin, choose Integrate any other application you don't find in the gallery (Non-gallery).
- Open the new app → Single sign-on → SAML.
- In step 1 (Basic SAML Configuration) paste the Vornin SP Entity ID as Identifier, SP ACS URL as Reply URL, leave Sign-on URL blank.
- In step 3 (SAML Certificates) download the Certificate (Base64).
- From step 4 (Set up Vornin) copy Login URL and Microsoft Entra Identifier.
- In Vornin Settings → SAML 2.0 SSO: paste Microsoft Entra Identifier into IdP Entity ID, Login URL into IdP SSO URL, the certificate file contents into the cert box. Enable and Save.
Google Workspace
- In Google Admin: Apps → Web and mobile apps → Add app → Add custom SAML app.
- Copy the SSO URL and Entity ID, download the Certificate.
- Paste the Vornin SP ACS URL and SP Entity ID into Google's "Service provider details" form. Set Name ID format to EMAIL.
- Add an attribute mapping: Primary email → Email.
- Back in Vornin Settings → SAML 2.0 SSO, paste Google's three values, enable, save. In Google Admin grant the app to the right organisational units.
PingFederate / JumpCloud / OneLogin
Same pattern: create a SAML SP integration in the IdP, paste Vornin's three SP URLs into the IdP's SP form, paste the IdP's entity ID + SSO URL + signing certificate back into Vornin Settings → SAML 2.0 SSO, enable.
Notes. SAML 2.0 SSO is on the Business plan and above. The asserted email must already match an existing Vornin user with a tenant membership — JIT user creation is a Phase 2 feature. Single Logout (SLO) and IdP-initiated flows are also Phase 2.
Social login
Sign in to Vornin with Google or GitHub. The first time you use a social provider with an email Vornin has never seen, you'll be sent through the normal sign-up wizard with your email pre-filled. If your email already has a Vornin account, your social identity is automatically linked the first time you use it — no extra confirmation step required, because Google and GitHub already verified the email.
Two-factor (TOTP) requirements still apply to social sign-in: if your workspace requires TOTP, you'll be prompted after the social round trip.
Two-factor authentication (TOTP)
TOTP (Time-based One-Time Password) adds a second factor on top of the magic link. It is compatible with any RFC 6238 authenticator — Microsoft Authenticator, Google Authenticator, 1Password, Authy, etc.
Step-by-step: enrol your authenticator
- Install an authenticator app on your phone (see the list above).
- Sign in to Vornin, then visit
/auth/totp-setup(or follow the "Enable TOTP" prompt if it's shown to you). - Scan the displayed QR code with your authenticator app. If you can't scan, use the manual key below the QR code and add it as type "Time-based" in the app.
- Enter the 6-digit code your authenticator shows and click Verify.
- Save the recovery codes Vornin shows you. Store them in a password manager — they are the only way to regain access if you lose your phone.
See RFC 6238 for the underlying algorithm.
Tenant-wide TOTP enforcement
Owners and Admins can require every member of the tenant to enrol a TOTP authenticator before they can sign in. When enabled, members without TOTP are redirected to /auth/totp-setup at their next login. Existing sessions continue until expiry.
API Keys
API keys grant programmatic access to the same endpoints the UI uses. All keys are tied to a tenant and respect the same role-based authorisation as the user who created them.
Step-by-step: create a key
- Go to Admin → API Keys.
- Click Generate API Key.
- Give the key a descriptive name (e.g. ci-pipeline, grafana-integration) so it's easy to revoke later.
- Select the minimum role scope required — prefer Member (read-only-ish) over Admin unless the caller must create scans.
- Optionally set an expiry date.
- Click Create. Copy the key immediately — it starts with
cvk_and is shown only once. - Use the key with Bearer-token authentication:
Authorization: Bearer cvk_YOUR_API_KEY
Rotating & revoking
- To rotate: create a new key, deploy it to the caller, then delete the old one.
- To revoke immediately: go to Admin → API Keys and click Revoke on the affected row. All in-flight requests using that key start receiving
401 Unauthorizedon the next request.
SCIM 2.0 User Provisioning
Vornin exposes a SCIM 2.0 provisioning endpoint so identity providers (Azure AD / Entra ID, Okta, JumpCloud, OneLogin) can automate user lifecycle — new hires get access the moment they're added to the right IdP group, and leavers are deactivated automatically when their IdP account is removed.
SCIM is provisioning only; sign-in uses the Entra ID SSO or magic-link flow covered above. The two systems are complementary: SCIM creates the user, SSO authenticates them.
Endpoint
https://app.vornin.com/scim/v2
Supported resources:
GET /Users— list users (supportsstartIndex,count, and filtersuserName eq "...",emails[value eq "..."],active eq true|false)POST /Users— provision a new user; creates theAppUserrecord and the tenant membership in one shotGET /Users/{id}— fetch a single userPUT /Users/{id}— replace (idempotent upsert)PATCH /Users/{id}— partial update (supportsactive,displayName,userName)DELETE /Users/{id}— deprovisioning; deactivates the user (soft delete; preserved for audit)GET /Groups,GET /Groups/all-users— read-only; returns a single synthetic all users group per tenantGET /ServiceProviderConfig,GET /ResourceTypes,GET /Schemas— discovery metadata (per RFC 7644 §4)
Step-by-step: enable SCIM
- Go to Admin → Integrations → SCIM.
- Click Generate SCIM token. Copy the token immediately — it starts with
scim_and is shown only once. - In your IdP's provisioning UI, paste:
- Tenant URL:
https://app.vornin.com/scim/v2 - Secret token: the
scim_...value
- Tenant URL:
- Run the IdP's Test connection action. It should return Success.
- Map attributes (IdP-side): at minimum
userName,emails[primary].value,displayName,active. Vornin tolerates missinggivenName/familyName. - Save the provisioning configuration in the IdP. New users assigned to the Vornin app will appear in the customer portal within the IdP's sync interval (typically 20–40 minutes for Azure AD).
Authentication
Authorization: Bearer scim_YOUR_TOKEN
SCIM tokens are separate from REST-API keys (cvk_). They are tenant-scoped, stored as SHA-256 hashes, and rotatable; generating a new token revokes the previous one immediately.
Behavior notes
- New users are added with Member role. Promote to Admin / Owner manually in the app if required.
- Deprovisioning via
DELETE /Users/{id}deactivates the account (soft delete). Historical audit / vulnerability-assignment references are preserved. - Group management is read-only in this release. Vornin's role model is per-tenant (Member / Admin / Owner) and not currently synced from IdP groups — promote admins in-app.
- SCIM endpoints do not count against the
/api/v1rate limit. They have their own higher ceiling intended for bulk sync.
Webhooks
Webhooks deliver real-time scan and vulnerability events to any HTTPS endpoint you control — use them to wire Vornin into Slack / Teams bridges, incident-management platforms, or internal notification services. Each delivery is a signed HTTP POST with a JSON payload.
Step-by-step: add a webhook
- Go to Admin → Integrations → Webhooks → Add Webhook.
- Enter a name and the endpoint URL (must be HTTPS).
- Set the minimum severity filter (e.g. High to only ship Critical and High findings).
- Pick the events you want to subscribe to (see the table below).
- Click Save. Vornin generates a signing secret — copy it and store it on your endpoint server; it is shown only once.
- Click Test to send a signed sample payload to your endpoint. The UI shows the response code and latency.
- On your endpoint, verify every incoming request by recomputing HMAC-SHA256 over the raw request body using your signing secret and comparing it to the
X-Vornin-Signatureheader. Reject anything that doesn't match.
Events
| Event | Fires when | Payload highlights |
|---|---|---|
scan.complete | A scan finishes (success or failure) | Scan ID, status, start/end, target count, finding counts |
vulnerability.found | A new vulnerability is first detected | Vulnerability ID, title, severity, affected host, scanner |
sla.breach | An open vulnerability crosses its SLA deadline | Vulnerability ID, title, severity, affected host, SlaDueAt |
Jira integration is available for automatic ticket creation on vulnerability.found.
CSV Export
Export your vulnerability data as CSV from the Vulnerabilities page using the "Export CSV" button. The export includes title, severity, status, host, port, scanner, CVE, CVSS score, detection dates, SLA deadline, and assignee.
Import Scan Results
Import vulnerability findings from third-party tools under Import Results. Supported formats:
- CSV — columns: Title, Severity, Host, Port, Description, Solution, CVE
- Nessus — .nessus XML export files
- OpenVAS — XML report export files
- JSON — array of finding objects
Preview findings before importing. Imported results are created as a completed scan and run through the standard vulnerability tracking pipeline (dedup, compliance mapping, SLA assignment).
Target Health Scores
Each target on the Targets page displays a health score (A–F) calculated from its open vulnerabilities:
- Base score: 100
- Critical vulnerability: -20 points
- High vulnerability: -10 points
- Medium vulnerability: -3 points
- Low vulnerability: -1 point
Scores update automatically as vulnerabilities are found and resolved. Use health scores to prioritize which targets need attention first.
Cloud Security Scanning
Vornin actively scans your AWS, Azure, and GCP environments using read-only SDK calls — no agents required, no write access needed. Each scan runs 41 live checks across IAM, storage, key management, network exposure, and logging, then maps every finding to your active compliance frameworks (NIS2, DORA, PCI DSS, ISO 27001, HIPAA, and more).
- AWS (15 checks): public S3 buckets, MFA on root, unused IAM access keys, CloudTrail logging, KMS key rotation, open security groups, RDS public access, Lambda public URLs, Config recorder, unused IAM roles, S3 versioning, root access key presence, VPC flow logs, password policy, EC2 IMDSv2 enforcement.
- Azure (11 checks): NSG open SSH/RDP, storage public blob access, storage infrastructure encryption, Key Vault soft-delete, Key Vault public firewall, SQL TDE, SQL Azure AD admin, VM public IP exposure, NSG flow logs, Defender for Cloud tier, container registry admin user.
- GCP (15 checks — 100% coverage): stale service account keys, public GCS buckets, open VPC firewall on 22/3389, Cloud SQL public IP, audit log config, primitive IAM role bindings, public service accounts, buckets without uniform bucket-level access, default network presence, serial-port-enabled instances, instances using default Compute SA, Cloud SQL without backups, audit log sink to long-term storage, KMS key rotation, GKE legacy auth (basic auth / client cert).
Step-by-step: AWS
- In the AWS console, create an IAM user (or role) and attach the managed policy
SecurityAudit. This grants read-only visibility into security-relevant services without any write capability. - Generate an access key ID and secret access key for that IAM user. See Managing access keys for IAM users.
- In Vornin, go to Cloud Connections → Add Connection, choose AWS, paste the access key ID + secret, and optionally restrict to specific regions.
- Click Test Connection to confirm the credentials resolve.
Step-by-step: Azure
- In Microsoft Entra ID, register an application and create a service principal.
- On the subscriptions you want to scan, assign the Reader built-in role to the new service principal.
- Note the Tenant ID, Client ID, and create a Client Secret for the app.
- In Vornin, go to Cloud Connections → Add Connection, choose Azure, and paste the three values plus the subscription ID.
Step-by-step: Google Cloud
- In GCP IAM, create a service account and grant it the Security Reviewer role on the projects or the organisation you want to scan.
- Create a JSON key for the service account and download it.
- In Vornin, go to Cloud Connections → Add Connection, choose GCP, and upload (or paste) the JSON key.
Cloud findings surface in the Vulnerabilities list with Scanner = CloudSecurity and are mapped to the same compliance frameworks as your other scanner results.
Code Repositories
Connecting a code repository unlocks the SAST, Secret, and Dependency scanners. Vornin clones the selected branch into a temporary directory for each scan, analyses it, and deletes the clone when done — no code is stored after the scan completes.
Step-by-step: GitHub
- In GitHub, create a Personal Access Token. The classic PAT only needs the
reposcope (read-only is sufficient for public repos). See Managing personal access tokens, or for a fine-grained token, Creating a fine-grained PAT (grant Contents: read + Metadata: read on the repos you want to scan). - Copy the token. It starts with
ghp_(classic) orgithub_pat_(fine-grained). - In Vornin, go to Repositories → Add Connection, choose GitHub, paste the token, and click Connect.
- Select the repositories you want to import and choose the default branch to scan (usually
mainormaster). You can change the branch later. - Trigger a scan from Scan Now and include the imported repos in the targets list.
Step-by-step: Azure DevOps
- In Azure DevOps, create a Personal Access Token scoped to Code (Read). See Use PATs to authenticate to Azure DevOps.
- Copy the token.
- In Vornin, go to Repositories → Add Connection, choose Azure DevOps, and paste the token plus your organization URL (e.g.
https://dev.azure.com/contoso). - Pick the project and repositories you want to import, and set the branch to scan.
- Trigger a scan from Scan Now and include the imported repos in the targets list.
The branch can be changed at any time from the Repositories page without reconnecting.
REST API
The Vornin API allows programmatic access to scans, vulnerabilities, and targets. Full interactive documentation is available at:
https://app.vornin.com/api-docs
Authenticate with an API key using the Authorization: Bearer cvk_YOUR_KEY header. The API supports creating scans, listing vulnerabilities, and downloading reports.
Generate an API key from Settings → API Keys in the app. Keys are tenant-scoped; choose Admin or Owner role for write endpoints (scan create, target create).
Python recipes
Copy-pasteable snippets using only the requests library. No SDK install required.
1. Auth + session setup
Reuse a requests.Session so TCP connections keep alive across calls — cuts wall-clock time roughly in half when you chain requests.
import os
import requests
BASE = "https://app.vornin.com/api/v1"
API_KEY = os.environ["VORNIN_API_KEY"] # cvk_...
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json",
})
2. Create a target
Adds a host/domain to the tenant's target list. Requires Admin or Owner API key.
r = session.post(f"{BASE}/targets", json={
"name": "Acme Production",
"host": "acme.example.com",
"environment": "Production",
})
r.raise_for_status()
target = r.json()
print("created target", target["id"])
3. Trigger a scan
Kicks off a scan and returns the scan ID. scannerTypes can be any subset of the fifteen engines (PortScan, SslTls, WebVulnerability, ApiSecurity, DnsSecurity, SubdomainEnum, SubdomainTakeover, Sast, SecretScan, DependencyScan, NucleiTemplate, Wordpress, ContainerImage, Kubernetes, CloudPosture).
r = session.post(f"{BASE}/scans", json={
"targetIds": [target["id"]],
"scannerTypes": ["SslTls", "Web", "DnsSecurity"],
"maxParallel": 3,
})
r.raise_for_status()
scan = r.json()
scan_id = scan["id"]
print("scan queued", scan_id)
4. Poll until the scan completes
The status field progresses Pending → Running → Completed (or Failed). A typical mixed scan takes 2–10 minutes; poll every 15 seconds to stay within rate limits on the Team tier.
import time
while True:
r = session.get(f"{BASE}/scans/{scan_id}")
r.raise_for_status()
status = r.json()["status"]
print("status:", status)
if status in ("Completed", "Failed"):
break
time.sleep(15)
5. List vulnerabilities for a scan
Returns a paginated list. severity accepts Critical, High, Medium, Low, Info. status accepts Open, Acknowledged, Resolved, Dismissed.
vulns = []
page = 1
while True:
r = session.get(f"{BASE}/vulnerabilities", params={
"scanId": scan_id,
"severity": "Critical",
"status": "Open",
"page": page,
"pageSize": 100,
})
r.raise_for_status()
batch = r.json()
vulns.extend(batch["items"])
if page * batch["pageSize"] >= batch["total"]:
break
page += 1
print(f"found {len(vulns)} critical open vulnerabilities")
for v in vulns[:5]:
print(f" - {v['title']} @ {v['affectedHost']}")
6. Mark a vulnerability resolved
Use status: "Resolved" when you've fixed it, or status: "Dismissed" with a reason if it's a false positive.
r = session.put(f"{BASE}/vulnerabilities/{vulns[0]['id']}", json={
"status": "Resolved",
"note": "Upgraded to nginx 1.27.1",
})
r.raise_for_status()
7. Download a PDF report
Executive, technical, or compliance reports. Severity filter optional — defaults to all.
r = session.get(
f"https://app.vornin.com/api/reports/{scan_id}/pdf",
params={"minSeverity": 3}, # Medium and above
)
r.raise_for_status()
with open(f"report-{scan_id}.pdf", "wb") as f:
f.write(r.content)
print("saved report")
8. CI/CD: fail a PR on new Critical findings
This is the headline recipe. Drop the script into your repo and point a GitHub Action at it — the build fails if the latest scan has any new Critical vulnerabilities.
GitHub Actions workflow (.github/workflows/vornin.yml):
name: Vornin security scan
on:
pull_request:
schedule:
- cron: "0 6 * * *" # daily at 06:00 UTC
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install requests
- run: python .github/scripts/vornin_gate.py
env:
VORNIN_API_KEY: ${{ secrets.VORNIN_API_KEY }}
VORNIN_TARGET_ID: ${{ vars.VORNIN_TARGET_ID }}
Script (.github/scripts/vornin_gate.py):
"""Fail the build if the latest Vornin scan has new Critical findings."""
import os
import sys
import time
import requests
BASE = "https://app.vornin.com/api/v1"
session = requests.Session()
session.headers.update({"Authorization": f"Bearer {os.environ['VORNIN_API_KEY']}"})
target_id = int(os.environ["VORNIN_TARGET_ID"])
# trigger a scan
scan_id = session.post(f"{BASE}/scans", json={
"targetIds": [target_id],
"scannerTypes": ["SslTls", "Web", "DnsSecurity", "Sast", "SecretScan", "Dependency"],
}).json()["id"]
# wait for completion (max 20 min)
deadline = time.time() + 20 * 60
while time.time() < deadline:
status = session.get(f"{BASE}/scans/{scan_id}").json()["status"]
if status in ("Completed", "Failed"):
break
time.sleep(20)
else:
sys.exit("Scan timed out after 20 minutes")
# gate: fail if there are any Critical findings
r = session.get(f"{BASE}/vulnerabilities", params={
"scanId": scan_id,
"severity": "Critical",
"status": "Open",
"pageSize": 1,
})
critical_count = r.json()["total"]
if critical_count > 0:
print(f"::error::Vornin found {critical_count} critical vulnerabilities in this PR")
sys.exit(1)
print(f"PASS: no new critical findings (scan {scan_id})")
Store VORNIN_API_KEY as a repository secret and VORNIN_TARGET_ID as a repository variable. The script exits 0 on pass, 1 on any Critical finding — so GitHub will red-cross the PR automatically.
Need a language other than Python, or a full-service SDK? Talk to us — we'll prioritise it if there's demand.